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}