001/* An attribute representing the size of a component. 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 027 */ 028package ptolemy.actor.gui; 029 030import java.awt.Component; 031import java.awt.Dimension; 032import java.awt.Rectangle; 033import java.awt.event.ComponentEvent; 034import java.awt.event.ComponentListener; 035 036import javax.swing.JComponent; 037 038import ptolemy.data.IntMatrixToken; 039import ptolemy.data.expr.Parameter; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.InternalErrorException; 042import ptolemy.kernel.util.NameDuplicationException; 043import ptolemy.kernel.util.NamedObj; 044import ptolemy.kernel.util.Settable; 045import ptolemy.kernel.util.Workspace; 046 047/////////////////////////////////////////////////////////////////// 048//// SizeAttribute 049 050/** 051 This attribute stores the width and height of a graphical component. 052 The token in this attribute is an IntMatrixToken containing a matrix 053 of dimension 1x2, containing the width and the height, in that order. 054 By default, this attribute has visibility NONE, so the user will not 055 see it in parameter editing dialogs. 056 <p> 057 Note that this attribute is typically used to record the size of 058 a component within a frame (a top-level window). To record the size 059 and position of the frame, use WindowPropertiesAttribute. 060 061 @author Edward A. Lee 062 @version $Id$ 063 @since Ptolemy II 1.0 064 @Pt.ProposedRating Red (eal) 065 @Pt.AcceptedRating Red (johnr) 066 @see WindowPropertiesAttribute 067 */ 068public class SizeAttribute extends Parameter implements ComponentListener { 069 /** Construct an attribute with the given name contained by the specified 070 * entity. The container argument must not be null, or a 071 * NullPointerException will be thrown. This attribute will use the 072 * workspace of the container for synchronization and version counts. 073 * If the name argument is null, then the name is set to the empty string. 074 * Increment the version of the workspace. 075 * @param container The container. 076 * @param name The name of this attribute. 077 * @exception IllegalActionException If the attribute is not of an 078 * acceptable class for the container, or if the name contains a period. 079 * @exception NameDuplicationException If the name coincides with 080 * an attribute already in the container. 081 */ 082 public SizeAttribute(NamedObj container, String name) 083 throws IllegalActionException, NameDuplicationException { 084 super(container, name); 085 setVisibility(Settable.NONE); 086 087 // The following line, if uncommented, results in 088 // icons that are defined in an external file always being 089 // exported along with the model that defines them. This bloats 090 // the MoML files with information that is not needed. I suspect 091 // the line was put there because it wasn't clear that you need 092 // to invoke File->Save in a submodel if you want the location 093 // and position of the submodel window to be saved. It is not 094 // sufficient to invoke save just at the top level. 095 // setPersistent(true); 096 } 097 098 /////////////////////////////////////////////////////////////////// 099 //// public methods //// 100 101 /** Clone the attribute into the specified workspace. This calls the 102 * base class and then sets the attribute public members to refer 103 * to the attributes of the new attribute. 104 * @param workspace The workspace for the new attribute 105 * @return A new director. 106 * @exception CloneNotSupportedException If a derived class contains 107 * an attribute that cannot be cloned. 108 */ 109 @Override 110 public Object clone(Workspace workspace) throws CloneNotSupportedException { 111 SizeAttribute newObject = (SizeAttribute) super.clone(workspace); 112 newObject._listeningTo = null; 113 return newObject; 114 } 115 116 /** Do nothing. This method is 117 * invoked when the component has been made invisible. 118 * @param event The component event. 119 */ 120 @Override 121 public void componentHidden(ComponentEvent event) { 122 } 123 124 /** Do nothing. This method is 125 * invoked when the component's position changes. 126 * @param event The component event. 127 */ 128 @Override 129 public void componentMoved(ComponentEvent event) { 130 } 131 132 /** Record the new size. This method is 133 * invoked when the component's size changes. 134 * @param event The component event. 135 */ 136 @Override 137 public void componentResized(ComponentEvent event) { 138 // FIXME: Due to Swing's lame approach to sizes, 139 // the size that is reported by this event is actually, 140 // apparently, a random number, the off by just enough 141 // from the actual size to cause scroll bars to be 142 // squished and the progress bar to not be shown. 143 // So we don't record the size. 144 // recordSize(_listeningTo); 145 } 146 147 /** Do nothing. This method is 148 * invoked when the component has been made visible. 149 * @param event The component event. 150 */ 151 @Override 152 public void componentShown(ComponentEvent event) { 153 } 154 155 /** Set the value of the attribute to match those of the specified 156 * component. 157 * @param component The component whose size is to be recorded. 158 */ 159 public void recordSize(Component component) { 160 try { 161 Rectangle bounds = component.getBounds(); 162 setToken("[" + bounds.width + ", " + bounds.height + "]"); 163 // Not clear why the following is needed, but if it isn't there, 164 // then window properties may not be recorded. 165 propagateValue(); 166 } catch (IllegalActionException ex) { 167 throw new InternalErrorException("Can't set bounds value!"); 168 } 169 } 170 171 /** Set the size of the specified component to match the 172 * current value of the attribute. If the value of the attribute 173 * has not been set, then do nothing. If it has not already 174 * done so, this method also registers with the component 175 * as a listener for component events like resizing. 176 * @param component The component whose size is to be set. 177 * @return True if successful. 178 */ 179 public boolean setSize(Component component) { 180 if (component == null) { 181 if (_listeningTo != null) { 182 _listeningTo.removeComponentListener(this); 183 _listeningTo = null; 184 } 185 return true; 186 } 187 if (_listeningTo != component) { 188 if (_listeningTo != null) { 189 _listeningTo.removeComponentListener(this); 190 } 191 192 component.addComponentListener(this); 193 _listeningTo = component; 194 } 195 196 try { 197 IntMatrixToken token = (IntMatrixToken) getToken(); 198 199 if (token != null) { 200 int width = token.getElementAt(0, 0); 201 int height = token.getElementAt(0, 1); 202 203 // NOTE: As usual with swing, it's not obvious what the 204 // right way to do this is. The following seems to work, 205 // found by trial and error. Even then, the layout 206 // manager feels free to override it. 207 Dimension dimension = new Dimension(width, height); 208 component.setSize(dimension); 209 210 // NOTE: If it's a JComponent, the setSize() is 211 // insufficient to set the size (you will have to ask 212 // Sun why this is so). We also have to do the 213 // following. 214 if (component instanceof JComponent) { 215 ((JComponent) component).setPreferredSize(dimension); 216 ((JComponent) component).setMinimumSize(dimension); 217 } 218 } else { 219 // Unset the size. 220 if (component instanceof JComponent) { 221 ((JComponent) component).setPreferredSize(null); 222 } 223 } 224 225 return true; 226 } catch (Exception ex) { 227 return false; 228 } 229 } 230 231 /////////////////////////////////////////////////////////////////// 232 //// private variables //// 233 234 /** The component we are listening to. */ 235 private Component _listeningTo; 236 // FIXME: should the above we a weak reference like what we have 237 // for WindowPropertiesAttribute? 238 239}