001/* A tableau representing a dialog window.
002
003 Copyright (c) 2003-2013 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 */
027package ptolemy.actor.gui;
028
029import java.awt.Frame;
030import java.lang.reflect.Constructor;
031import java.util.Iterator;
032
033import javax.swing.JFrame;
034
035import ptolemy.kernel.Entity;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.KernelException;
038import ptolemy.kernel.util.NameDuplicationException;
039import ptolemy.kernel.util.NamedObj;
040import ptolemy.util.MessageHandler;
041
042///////////////////////////////////////////////////////////////////
043//// DialogTableau
044
045/**
046 A tableau representing a Dialog in a toplevel window.
047 <p>
048 DialogTableau is just like all the other XXXTableau classes except that the
049 Frame associated with DialogTableau is not an extension of TableauFrame, and,
050 ultimately, the Top class. The reason being that Top adorns the GUI
051 manifestation with the normal status bar which isn't appropriate for a
052 dialog.
053 In addition, the created dialog is not a JDialog, but a JFrame. And, the
054 created dialog is non-modal.
055 <p>
056 There can be any number of instances of this class in an effigy, however,
057 there
058 can only be one each for the model represented by the effigy, and one each of
059 the actors that are part of the model.
060
061 @author  Rowland R Johnson
062 @version $Id$
063 @since Ptolemy II 4.0
064 @Pt.ProposedRating Red (rowland)
065 @Pt.AcceptedRating Red (cxh)
066 @see Effigy
067 */
068public class DialogTableau extends Tableau {
069    /** Construct a new tableau for the model represented by the given effigy.
070     *  Use setFrame() to specify the Dialog after construction.
071     *  @param container The container.
072     *  @param name The name.
073     *  @exception IllegalActionException If the container does not accept
074     *   this entity (this should not occur).
075     *  @exception NameDuplicationException If the name coincides with an
076     *   attribute already in the container.
077     */
078    public DialogTableau(Effigy container, String name)
079            throws IllegalActionException, NameDuplicationException {
080        super(container.workspace());
081
082        setName(name);
083        setContainer(container);
084    }
085
086    ///////////////////////////////////////////////////////////////////
087    ////                         public methods                    ////
088
089    /** Create a tableau for the specified dialog. First look to see
090     *  if a dialog already exists. If so, then just return that one.
091     *  @param parent The Frame parent
092     *  @param configuration The configuration
093     *  @param effigy The Effigy containing the model that needs a dialog.
094     *  @param dialogClass The Dialog class to create.
095     *  @param target The entity that needs the Dialog
096     *  @return DialogTableau
097     */
098    public static DialogTableau createDialog(Frame parent,
099            Configuration configuration, Effigy effigy, Class dialogClass,
100            Entity target) {
101        if (PtolemyDialog.class.isAssignableFrom(dialogClass)) {
102            // First see whether the effigy already contains a dialog of
103            // dialogClas on this entity.
104            Iterator dialogs = effigy.entityList(DialogTableau.class)
105                    .iterator();
106
107            while (dialogs.hasNext()) {
108                DialogTableau dialogTableau = (DialogTableau) dialogs.next();
109                PtolemyDialog existingDialog = (PtolemyDialog) dialogTableau
110                        .getFrame();
111
112                if (existingDialog != null
113                        && existingDialog.getClass() == dialogClass
114                        && dialogTableau.hasTarget(target)) {
115                    return dialogTableau;
116                }
117            }
118
119            // Now, do the same test on the container of the effigy.
120            NamedObj container = effigy.getContainer();
121
122            if (container != null && container instanceof PtolemyEffigy) {
123                dialogs = ((PtolemyEffigy) container)
124                        .entityList(DialogTableau.class).iterator();
125
126                while (dialogs.hasNext()) {
127                    DialogTableau dialogTableau = (DialogTableau) dialogs
128                            .next();
129                    PtolemyDialog existingDialog = (PtolemyDialog) dialogTableau
130                            .getFrame();
131
132                    if (existingDialog.getClass() == dialogClass
133                            && dialogTableau.hasTarget(target)) {
134                        return dialogTableau;
135                    }
136                }
137            }
138        }
139
140        // A DialogTableau doesn't exist, so create one.
141        DialogTableau newDialogTableau;
142
143        try {
144            newDialogTableau = new DialogTableau(effigy,
145                    effigy.uniqueName("dialog"));
146
147            PtolemyDialog dialog = null;
148            Constructor[] constructors = dialogClass.getConstructors();
149            Constructor constructor = null;
150
151            for (Constructor constructor2 : constructors) {
152                Class[] pType = constructor2.getParameterTypes();
153
154                if (pType.length == 4 && pType[0] == DialogTableau.class
155                        && pType[1] == Frame.class && pType[2] == Entity.class
156                        && pType[3] == Configuration.class) {
157                    constructor = constructor2;
158                    break;
159                }
160            }
161
162            if (constructor != null) {
163                Object[] args = new Object[4];
164                args[0] = newDialogTableau;
165                args[1] = parent;
166                args[2] = target;
167                args[3] = configuration;
168                dialog = (PtolemyDialog) constructor.newInstance(args);
169            }
170
171            if (dialog == null) {
172                throw new KernelException(target, null,
173                        "Can't create a " + dialogClass);
174            }
175
176            newDialogTableau.setFrame(dialog);
177            return newDialogTableau;
178        } catch (Throwable throwable) {
179            MessageHandler.error("Failed to create a DialogTableau for "
180                    + target.getFullName(), throwable);
181        }
182
183        return null;
184    }
185
186    /** Get the target associated with this DialogTableau. Actually, the target
187     *  is associated with the frame that is associated with this DialogTableau.
188     * @return target The Entity that this DialogTableau is associated with.
189     */
190    public Entity getTarget() {
191        JFrame dialogJFrame = getFrame();
192
193        if (dialogJFrame instanceof PtolemyDialog) {
194            PtolemyDialog dialog = (PtolemyDialog) dialogJFrame;
195            return dialog.getTarget();
196        }
197
198        return null;
199    }
200
201    /** Determines if a particular Entity is associated with this
202     *  DialogTableau.
203     * @param entity Entity that test is performed on.,
204     * @return true/false True if entity is associated with this DialogTableau.
205     */
206    public boolean hasTarget(Entity entity) {
207        Entity target = getTarget();
208
209        if (target != null && target == entity) {
210            return true;
211        }
212
213        return false;
214    }
215}