001/* A top-level frame for editing the layout of a customizable run control panel. 002 003 Copyright (c) 2007-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.Component; 031import java.awt.Container; 032import java.util.ArrayList; 033import java.util.HashMap; 034import java.util.List; 035import java.util.Map; 036 037import javax.swing.JTabbedPane; 038 039import org.mlc.swing.layout.ContainerLayout; 040import org.mlc.swing.layout.LayoutConstraintsManager; 041import org.mlc.swing.layout.LayoutFrame; 042import org.mlc.swing.layout.MultiContainerFrame; 043 044import ptolemy.actor.CompositeActor; 045import ptolemy.actor.gui.Tableau; 046import ptolemy.actor.gui.TableauFrame; 047import ptolemy.kernel.util.Attribute; 048import ptolemy.kernel.util.ConfigurableAttribute; 049import ptolemy.kernel.util.IllegalActionException; 050import ptolemy.kernel.util.InternalErrorException; 051import ptolemy.kernel.util.KernelException; 052import ptolemy.util.CancelException; 053import ptolemy.util.MessageHandler; 054 055/////////////////////////////////////////////////////////////////// 056//// RunLayoutFrame 057 058/** 059 A top-level frame for editing the layout of a customizable run control panel. 060 <p> 061 This is based on the LayoutFrame class by Michael Connor (mlconnor@yahoo.com). 062 063 @see LayoutFrame 064 @author Edward A. Lee 065 @version $Id$ 066 @since Ptolemy II 8.0 067 @Pt.ProposedRating Yellow (eal) 068 @Pt.AcceptedRating Red (cxh) 069 */ 070@SuppressWarnings("serial") 071public class RunLayoutFrame extends TableauFrame 072 implements MultiContainerFrame { 073 /** Construct a frame to control the specified Ptolemy II model. 074 * After constructing this, it is necessary 075 * to call setVisible(true) to make the frame appear. 076 * This is typically accomplished by calling show() on 077 * enclosing tableau. 078 * @param model The model to put in this frame, or null if none. 079 * @param tableau The tableau responsible for this frame. 080 * @param pane The run pane whose layout is being edited. 081 * @exception IllegalActionException If the XML to be parsed has errors. 082 */ 083 public RunLayoutFrame(CompositeActor model, Tableau tableau, 084 CustomizableRunPane pane) throws IllegalActionException { 085 super(tableau); 086 _model = model; 087 _constraintsManager = pane.getLayoutConstraintsManager(); 088 _pane = pane; 089 090 List<ContainerLayout> layouts = _constraintsManager.getLayouts(); 091 for (int index = 0; index < layouts.size(); index++) { 092 ContainerLayout containerLayout = layouts.get(index); 093 Container container = _constraintsManager 094 .getContainer(containerLayout); 095 if (container == null) { 096 // If data is malformed, issue a warning and proceed. 097 try { 098 MessageHandler.warning("A container with name " 099 + containerLayout.getName() 100 + " was found in the contstraints file but was not found in the container"); 101 } catch (CancelException ex) { 102 throw new IllegalActionException(model, "Canceled"); 103 } 104 105 } else { 106 addContainerLayout(containerLayout, container); 107 } 108 } 109 110 getContentPane().setLayout(new BorderLayout(3, 3)); 111 getContentPane().add(_tabs, BorderLayout.CENTER); 112 113 pack(); 114 } 115 116 /////////////////////////////////////////////////////////////////// 117 //// public methods //// 118 119 /** Add a container with the specified name. 120 * @param name The name of the container. 121 * @param container The container. 122 */ 123 @Override 124 public void addContainer(String name, Container container) { 125 // check to see if another panel with this name already exists 126 ContainerLayout layout = _constraintsManager.getContainerLayout(name); 127 if (layout != null) { 128 throw new IllegalArgumentException( 129 "A container with name " + name + " already exists"); 130 } 131 132 layout = new ContainerLayout(name, "pref", "pref"); 133 _constraintsManager.addLayout(layout); 134 container.setLayout(layout); 135 _newLayouts.add(layout); 136 137 addContainerLayout(layout, container); 138 } 139 140 /** Return true if the frame has a container with the specified name. 141 * @param name The name of the container. 142 * @return true if the frame has a container with the specified name. 143 */ 144 @Override 145 public boolean hasContainer(String name) { 146 return _constraintsManager.getContainerLayout(name) != null; 147 } 148 149 /** Remove the container with the specified name. 150 * This may throw an InternalErrorException if the container does not exist. 151 * @param name The name of the container. 152 */ 153 @Override 154 public void removeContainer(String name) { 155 ContainerLayout layout = _constraintsManager.getContainerLayout(name); 156 if (layout == null) { 157 throw new InternalErrorException( 158 "Container " + name + " does not exist"); 159 } 160 // Also have to remove any contained containers! 161 Container container = _constraintsManager.getContainer(layout); 162 Component[] components = container.getComponents(); 163 for (Component component2 : components) { 164 if (component2 instanceof Container) { 165 String componentName = layout.getComponentName(component2); 166 if (hasContainer(componentName)) { 167 removeContainer(componentName); 168 } 169 } 170 } 171 _constraintsManager.removeLayout(layout); 172 PtolemyFormEditor editor = _editors.get(layout); 173 _tabs.remove(editor); 174 _newLayouts.remove(layout); 175 } 176 177 /////////////////////////////////////////////////////////////////// 178 //// protected methods //// 179 180 /** Close the window. This overrides the base class to record 181 * the modified layout, if it has been modified. 182 * @return False if the user cancels on a save query. 183 */ 184 @Override 185 protected boolean _close() { 186 if (super._close()) { 187 // Save the XML. 188 // FIXME: Do this only if the layout has been modified. 189 String xml = _constraintsManager.getXML(); 190 Attribute layoutAttribute = _model 191 .getAttribute("_runLayoutAttribute"); 192 if (layoutAttribute == null) { 193 try { 194 layoutAttribute = new ConfigurableAttribute(_model, 195 "_runLayoutAttribute"); 196 } catch (KernelException e) { 197 throw new InternalErrorException(e); 198 } 199 } 200 if (!(layoutAttribute instanceof ConfigurableAttribute)) { 201 MessageHandler.error("Model contains an attribute named " 202 + "'_runLayoutAttribute' that is not the right class " 203 + "to save a run layout in: " + _model.getFullName()); 204 } 205 try { 206 ((ConfigurableAttribute) layoutAttribute).configure(null, null, 207 xml); 208 } catch (Exception e) { 209 throw new InternalErrorException(e); 210 } 211 return true; 212 } 213 return false; 214 } 215 216 /////////////////////////////////////////////////////////////////// 217 //// protected variables //// 218 219 /** The run pane whose layout is being edited. */ 220 protected CustomizableRunPane _pane; 221 222 /** The associated model. */ 223 protected CompositeActor _model; 224 225 /////////////////////////////////////////////////////////////////// 226 //// private methods //// 227 228 /** Add an instance of PtolemyFormEditor for the specified containerLayout 229 * to the specified container. 230 * @param containerLayout The layout to edit. 231 * @param container The container into which to put the editor. 232 */ 233 private void addContainerLayout(ContainerLayout containerLayout, 234 Container container) { 235 PtolemyFormEditor formEditor = new PtolemyFormEditor(this, 236 containerLayout, container); 237 _editors.put(containerLayout, formEditor); 238 _tabs.addTab(containerLayout.getName(), formEditor); 239 } 240 241 /////////////////////////////////////////////////////////////////// 242 //// private variables //// 243 244 /** The constraints manager being edited. */ 245 private LayoutConstraintsManager _constraintsManager; 246 247 /** Set of editors indexed by layout. */ 248 private Map<ContainerLayout, PtolemyFormEditor> _editors = new HashMap<ContainerLayout, PtolemyFormEditor>(); 249 250 /** A list of new layouts. */ 251 private List<ContainerLayout> _newLayouts = new ArrayList<ContainerLayout>(); 252 253 /** Tabbed pane for showing nested layouts. */ 254 private JTabbedPane _tabs = new JTabbedPane(); 255}