001/* An Object for changing the style of parameters. 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.style; 029 030import java.util.ArrayList; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Map; 035 036import javax.swing.BoxLayout; 037 038import ptolemy.actor.gui.Configurer; 039import ptolemy.data.expr.Parameter; 040import ptolemy.gui.Query; 041import ptolemy.gui.QueryListener; 042import ptolemy.gui.Top; 043import ptolemy.kernel.util.Attribute; 044import ptolemy.kernel.util.IllegalActionException; 045import ptolemy.kernel.util.InternalErrorException; 046import ptolemy.kernel.util.KernelException; 047import ptolemy.kernel.util.NameDuplicationException; 048import ptolemy.kernel.util.NamedObj; 049import ptolemy.kernel.util.Settable; 050import ptolemy.moml.MoMLChangeRequest; 051 052/////////////////////////////////////////////////////////////////// 053//// StyleConfigurer 054 055/** 056 This class is an editor for the styles of the parameters of an object. 057 It allows a user to graphically change the ParameterEditorStyles contained 058 within the user settable attributes of a named object. 059 It is very similar in spirit and style to Configurer, which edits the actual 060 values of the attributes. 061 <p> 062 The restore() method restores the values of the parameters of the 063 object to their values when this object was created. This can be used 064 in a modal dialog to implement a cancel button, which restores 065 the styles to those before the dialog was opened. 066 067 @see ptolemy.actor.gui.Configurer 068 @see ParameterEditorStyle 069 @author Steve Neuendorffer and Edward A. Lee 070 @version $Id$ 071 @since Ptolemy II 1.0 072 @Pt.ProposedRating Yellow (neuendor) 073 @Pt.AcceptedRating Yellow (neuendor) 074 */ 075@SuppressWarnings("serial") 076public class StyleConfigurer extends Query implements QueryListener { 077 /** Construct a configurer for the specified object. 078 * @param object The object to configure. 079 * @exception IllegalActionException If the specified object has 080 * no editor factories, and refuses to acceptable as an attribute 081 * an instance of EditorPaneFactory. 082 */ 083 public StyleConfigurer(NamedObj object) throws IllegalActionException { 084 super(); 085 this.addQueryListener(this); 086 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 087 088 _object = object; 089 090 setTextWidth(25); 091 092 try { 093 // FIXME this list should not be statically specified. 094 // Note that fixing this will probably move the accept method 095 // into some sort of factory object (instead of cloning 096 // existing styles). 097 // NOTE: These styles need to have a container so 098 // that exportMoML() doesn't generate XML header information. 099 Parameter container = new Parameter(); 100 _parameterStyles = new ParameterEditorStyle[8]; 101 _parameterStyles[0] = new LineStyle(container, "Line"); 102 _parameterStyles[1] = new CheckBoxStyle(container, "Check Box"); 103 _parameterStyles[2] = new ChoiceStyle(container, "Choice"); 104 _parameterStyles[3] = new EditableChoiceStyle(container, 105 "EditableChoice"); 106 _parameterStyles[4] = new TextStyle(container, "Text"); 107 _parameterStyles[5] = new FileChooserStyle(container, 108 "FileChooser"); 109 _parameterStyles[6] = new NotEditableLineStyle(container, "Fixed"); 110 _parameterStyles[7] = new HiddenStyle(container, "Hidden"); 111 } catch (NameDuplicationException ex) { 112 throw new InternalErrorException(ex.getMessage()); 113 } 114 115 Iterator parameters = object.attributeList(Settable.class).iterator(); 116 117 while (parameters.hasNext()) { 118 Settable param = (Settable) parameters.next(); 119 120 // Skip if the parameter is not visible. 121 if (!Configurer.isVisible(_object, param)) { 122 continue; 123 } 124 125 // Get the current style. 126 boolean foundOne = false; 127 Iterator styles = ((NamedObj) param) 128 .attributeList(ParameterEditorStyle.class).iterator(); 129 ParameterEditorStyle foundStyle = null; 130 131 while (styles.hasNext()) { 132 foundOne = true; 133 foundStyle = (ParameterEditorStyle) styles.next(); 134 } 135 136 List styleList = new ArrayList(); 137 138 // The index of the default; 139 int defaultIndex = 0; 140 141 _originalExpertMode = _object.getAttribute("_expertMode") != null; 142 if (param.getVisibility() == Settable.NOT_EDITABLE 143 && !_originalExpertMode && !foundOne) { 144 // If the parameter is set to NOT_EDITABLE visibility and not expert mode 145 // then only a fixed style is possible. 146 styleList.add("Fixed"); 147 defaultIndex = 0; 148 } else { 149 int count = 0; 150 151 // Reduce the list of parameters 152 for (int i = 0; i < _parameterStyles.length 153 && _parameterStyles[i] != null; i++) { 154 if (foundOne && _parameterStyles[i].getClass() == foundStyle 155 .getClass()) { 156 defaultIndex = count; 157 158 if (foundStyle.acceptable(param)) { 159 styleList.add(_parameterStyles[i].getName()); 160 count++; 161 } 162 } else if (_parameterStyles[i].acceptable(param)) { 163 styleList.add(_parameterStyles[i].getName()); 164 count++; 165 } 166 } 167 } 168 169 String[] styleArray = (String[]) styleList 170 .toArray(new String[styleList.size()]); 171 172 addChoice(param.getName(), param.getName(), styleArray, 173 styleArray[defaultIndex]); 174 } 175 176 // Add the expert mode box. 177 addCheckBox("expertMode", "expert mode", _originalExpertMode); 178 } 179 180 /////////////////////////////////////////////////////////////////// 181 //// public methods //// 182 183 /** Generate a change request to apply the changes. 184 * This is called to notify that one of the entries has changed. 185 * The name of the entry is passed as an argument. 186 * @param name The name of the entry. 187 */ 188 @Override 189 public void changed(String name) { 190 StringBuffer moml = new StringBuffer(); 191 192 // Treat the expertMode entry specially. 193 if (name.equals("expertMode")) { 194 Attribute previousExpert = _object.getAttribute("_expertMode"); 195 boolean isExpert = previousExpert != null; 196 boolean toExpert = getBooleanValue("expertMode"); 197 198 if (isExpert != toExpert) { 199 if (isExpert) { 200 moml.append("<deleteProperty name=\"_expertMode\"/>"); 201 } else { 202 moml.append("<property name=\"_expertMode\" " 203 + "class=\"ptolemy.kernel.util.SingletonAttribute\"/>"); 204 } 205 } 206 } else { 207 // Entry is not expertMode. 208 // Figure out which style is being requested. 209 ParameterEditorStyle found = null; 210 211 for (int i = 0; i < _parameterStyles.length && found == null; i++) { 212 if (getStringValue(name) 213 .equals(_parameterStyles[i].getName())) { 214 found = _parameterStyles[i]; 215 } 216 } 217 218 // First remove all pre-existing styles. 219 moml.append("<group>"); 220 221 Attribute param = _object.getAttribute(name); 222 moml.append("<property name=\"" + param.getName() + "\">"); 223 224 Iterator styles = param.attributeList(ParameterEditorStyle.class) 225 .iterator(); 226 boolean foundOne = false; 227 228 while (styles.hasNext()) { 229 foundOne = true; 230 231 ParameterEditorStyle style = (ParameterEditorStyle) styles 232 .next(); 233 moml.append( 234 "<deleteProperty name=\"" + style.getName() + "\"/>\n"); 235 } 236 237 if (foundOne) { 238 // Have to close and re-open the context to ensure 239 // that deletions occur before additions. 240 moml.append("</property>"); 241 moml.append("<property name=\"" + param.getName() + "\">"); 242 } 243 244 moml.append("<group name=\"auto\">"); 245 if (found != null) { 246 // Coverity: found could be null if there was an internal error 247 // and the parameter style was not found/ 248 moml.append(found.exportMoML("style")); 249 } 250 moml.append("</group></property></group>"); 251 } 252 253 MoMLChangeRequest change = new MoMLChangeRequest(this, _object, 254 moml.toString()); 255 _object.requestChange(change); 256 } 257 258 /** Request restoration of the parameter values to what they 259 * were when this object was created. The actual restoration 260 * occurs later, in the UI thread, in order to allow all pending 261 * changes to the parameter values to be processed first. 262 */ 263 public void restore() { 264 // This is done in the UI thread in order to 265 // ensure that all pending UI events have been 266 // processed. In particular, some of these events 267 // may trigger notification of new parameter values, 268 // which must not be allowed to occur after this 269 // restore is done. In particular, the default 270 // parameter editor has lines where notification 271 // of updates occurs when the line loses focus. 272 // That notification occurs some time after the 273 // window is destroyed. 274 Top.deferIfNecessary(new Runnable() { 275 @Override 276 public void run() { 277 // Treat the expertMode entry specially. 278 Attribute currentExpert = _object.getAttribute("_expertMode"); 279 boolean isExpert = currentExpert != null; 280 281 if (isExpert != _originalExpertMode) { 282 try { 283 if (isExpert) { 284 currentExpert.setContainer(null); 285 } else { 286 // FIXME: This won't propagate. 287 new Attribute(_object, "_expertMode"); 288 } 289 } catch (KernelException e) { 290 // This should not occur. 291 throw new InternalErrorException(e); 292 } 293 } 294 295 // FIXME: This code is nonsensical... _originalValues never 296 // gets anything added to it! 297 Iterator entries = _originalValues.entrySet().iterator(); 298 299 while (entries.hasNext()) { 300 Map.Entry entry = (Map.Entry) entries.next(); 301 Settable param = (Settable) _object 302 .getAttribute((String) entry.getKey()); 303 304 try { 305 param.setExpression((String) entry.getValue()); 306 } catch (IllegalActionException ex) { 307 throw new InternalErrorException( 308 "Cannot restore style value!"); 309 } 310 } 311 } 312 }); 313 } 314 315 /////////////////////////////////////////////////////////////////// 316 //// private variables //// 317 // The object that this configurer configures. 318 private NamedObj _object; 319 320 // Indicator of what the expert mode was upon entry. 321 private boolean _originalExpertMode = false; 322 323 // The original values of the parameters. 324 private Map _originalValues = new HashMap(); 325 326 // The list of the possible styles. 327 private ParameterEditorStyle[] _parameterStyles; 328}