001/* A top-level frame for a customizable run control panel.
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 */
027package ptolemy.actor.gui.run;
028
029import java.awt.BorderLayout;
030import java.awt.event.ActionEvent;
031import java.awt.event.ActionListener;
032import java.awt.event.KeyEvent;
033
034import javax.swing.JMenu;
035import javax.swing.JMenuItem;
036
037import ptolemy.actor.CompositeActor;
038import ptolemy.actor.gui.Effigy;
039import ptolemy.actor.gui.PtolemyEffigy;
040import ptolemy.actor.gui.TableauFrame;
041import ptolemy.kernel.util.Attribute;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.KernelException;
044import ptolemy.moml.MoMLChangeRequest;
045import ptolemy.util.CancelException;
046import ptolemy.util.MessageHandler;
047
048///////////////////////////////////////////////////////////////////
049//// CustomizableRunFrame
050
051/**
052 A top-level frame for a customizable run control panel.
053
054 @author Edward A. Lee
055 @version $Id$
056 @since Ptolemy II 8.0
057 @Pt.ProposedRating Yellow (eal)
058 @Pt.AcceptedRating Red (cxh)
059 */
060@SuppressWarnings("serial")
061public class CustomizableRunFrame extends TableauFrame {
062    /** Construct a frame to control the specified Ptolemy II model.
063     *  After constructing this, it is necessary
064     *  to call setVisible(true) to make the frame appear.
065     *  This is typically accomplished by calling show() on
066     *  enclosing tableau.
067     *  @param model The model to put in this frame, or null if none.
068     *  @param tableau The tableau responsible for this frame.
069     *  @exception IllegalActionException If the XML to be parsed has errors.
070     */
071    public CustomizableRunFrame(CompositeActor model, InterfaceTableau tableau)
072            throws IllegalActionException {
073        super(tableau);
074        _model = model;
075        getContentPane().setLayout(new BorderLayout());
076        _pane = new CustomizableRunPane(model, null);
077        getContentPane().add(_pane, BorderLayout.CENTER);
078    }
079
080    ///////////////////////////////////////////////////////////////////
081    ////                         protected methods                 ////
082
083    /** Add a Customize menu.
084     */
085    @Override
086    protected void _addMenus() {
087        super._addMenus();
088
089        JMenuItem[] customizeMenuItems = {
090                new JMenuItem("Customize Layout", KeyEvent.VK_C),
091                new JMenuItem("Revert to Default", KeyEvent.VK_R),
092                new JMenuItem("New Layout", KeyEvent.VK_N) };
093
094        // NOTE: This has to be initialized here rather than
095        // statically because this method is called by the constructor
096        // of the base class, and static initializers have not yet
097        // been run.
098        _customizeMenu = new JMenu("Customize");
099        _customizeMenu.setMnemonic(KeyEvent.VK_C);
100
101        CustomizeMenuListener customizeMenuListener = new CustomizeMenuListener();
102
103        // Set the action command and listener for each menu item.
104        for (JMenuItem customizeMenuItem : customizeMenuItems) {
105            customizeMenuItem.setActionCommand(customizeMenuItem.getText());
106            customizeMenuItem.addActionListener(customizeMenuListener);
107            _customizeMenu.add(customizeMenuItem);
108        }
109
110        _menubar.add(_customizeMenu);
111    }
112
113    ///////////////////////////////////////////////////////////////////
114    ////                         protected variables               ////
115
116    /** Customize menu for this frame. */
117    protected JMenu _customizeMenu;
118
119    /** The pane inside this frame. */
120    protected CustomizableRunPane _pane;
121
122    /** The associated model. */
123    protected CompositeActor _model;
124
125    ///////////////////////////////////////////////////////////////////
126    ////                         inner classes                     ////
127
128    /** Listener for customize menu commands. */
129    public class CustomizeMenuListener implements ActionListener {
130        @Override
131        public void actionPerformed(ActionEvent e) {
132            JMenuItem target = (JMenuItem) e.getSource();
133            String actionCommand = target.getActionCommand();
134            if (actionCommand.equals("Customize Layout")) {
135                // Layout frame to customize the layout.
136                try {
137                    Effigy effigy = getEffigy();
138                    LayoutTableau tableau = new LayoutTableau(
139                            (PtolemyEffigy) effigy, "Layout Run Panel", _pane);
140                    tableau.show();
141                } catch (KernelException ex) {
142                    try {
143                        MessageHandler.warning(
144                                "Failed to create layout customization frame: "
145                                        + ex);
146                    } catch (CancelException exception) {
147                    }
148                }
149            } else if (actionCommand.equals("Revert to Default")) {
150                // Delete the attribute, if it has been created.
151                Attribute attribute = _model
152                        .getAttribute("_runLayoutAttribute");
153                if (attribute != null) {
154                    // Do this in a change request so it can be undone.
155                    MoMLChangeRequest request = new MoMLChangeRequest(this,
156                            _model,
157                            "<deleteProperty name=\"_runLayoutAttribute\"/>") {
158                        @Override
159                        protected void _execute() throws Exception {
160                            super._execute();
161                            // Close this window and open a new one.
162                            // This must be done in the swing event thread.
163                            Runnable reOpen = new Runnable() {
164                                @Override
165                                public void run() {
166                                    // Create a new tableau.  Closing the old frame
167                                    // also results in removing the tableau.
168                                    PtolemyEffigy effigy = (PtolemyEffigy) getTableau()
169                                            .getContainer();
170                                    close();
171                                    try {
172                                        InterfaceTableau tableau = new InterfaceTableau(
173                                                effigy, effigy.uniqueName(
174                                                        "interfaceTableau"));
175                                        tableau.show();
176                                    } catch (KernelException e) {
177                                        MessageHandler.error(
178                                                "Failed to reopen run window.",
179                                                e);
180                                    }
181                                }
182                            };
183                            deferIfNecessary(reOpen);
184                        }
185                    };
186                    _model.requestChange(request);
187                    // FIXME: Should also close the RunLayoutFrame, if it is open.
188                }
189            } else if (actionCommand.equals("New Layout")) {
190                // Layout frame to create a new layout.
191                try {
192                    // Remove the existing layout.
193                    getContentPane().remove(_pane);
194                    // Define a default layout in XML.
195                    String xml = "<containers>" + "<container name=\"top\" "
196                            + "columnSpecs=\"default\" "
197                            + "rowSpecs=\"default\"> "
198                            + "</container></containers>";
199                    _pane = new CustomizableRunPane(_model, xml);
200                    getContentPane().add(_pane, BorderLayout.CENTER);
201                    pack();
202                    repaint();
203
204                    // Open the customization panel.
205                    Effigy effigy = getEffigy();
206                    LayoutTableau tableau = (LayoutTableau) effigy
207                            .getEntity("Layout Run Panel");
208                    if (tableau == null) {
209                        tableau = new LayoutTableau((PtolemyEffigy) effigy,
210                                "Layout Run Panel", _pane);
211                    }
212                    tableau.show();
213
214                    // Get this on top, since it is smaller, and will be obscured.
215                    setVisible(true);
216                } catch (KernelException ex) {
217                    try {
218                        MessageHandler.warning(
219                                "Failed to create layout customization frame: "
220                                        + ex);
221                    } catch (CancelException exception) {
222                    }
223                }
224            }
225        }
226    }
227}