001/* Add icons to certain actors 002 003 Copyright (c) 2002-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.moml.filter; 029 030import java.util.HashMap; 031import java.util.Iterator; 032 033import ptolemy.kernel.util.IllegalActionException; 034import ptolemy.kernel.util.NamedObj; 035import ptolemy.moml.MoMLParser; 036 037/////////////////////////////////////////////////////////////////// 038//// AddIcon 039 040/** Certain actors have specialized icons that display the value of 041 one of the parameters. This filter adds icons to those actors when 042 necessary. 043 044 @author Christopher Hylands, Edward A. Lee 045 @version $Id$ 046 @since Ptolemy II 2.0 047 @Pt.ProposedRating Red (cxh) 048 @Pt.AcceptedRating Red (cxh) 049 */ 050public class AddIcon extends MoMLFilterSimple { 051 /** If the attributeName is "class" and attributeValue names a 052 * class that has had its port names changed between releases, 053 * then substitute in the new port names. 054 * 055 * @param container The container for this attribute. 056 * in this method. 057 * @param element The XML element name. 058 * @param attributeName The name of the attribute. 059 * @param attributeValue The value of the attribute. 060 * @param xmlFile The file currently being parsed. 061 * @return the value of the attributeValue argument. 062 */ 063 @Override 064 public String filterAttributeValue(NamedObj container, String element, 065 String attributeName, String attributeValue, String xmlFile) { 066 // This method gets called many times by the MoMLParser, 067 // so we try to be smart about the number of comparisons 068 // and we try to group comparisons together so that we 069 // are not making the same comparison more than once. 070 if (attributeValue == null) { 071 // attributeValue == null is fairly common, so we check for 072 // that first 073 return null; 074 } 075 076 if (attributeName.equals("name")) { 077 // Save the name of the for later use if we see a "class" 078 _lastNameSeen = attributeValue; 079 080 if (_currentlyProcessingActorThatMayNeedAnIcon 081 && attributeValue.equals("_icon")) { 082 // We are processing an annotation and it already 083 // has _icon 084 _currentlyProcessingActorThatMayNeedAnIcon = false; 085 } 086 } 087 088 // If you change this class, you should run before and after 089 // timing tests on large moml files, a good command to run 090 // is: 091 // $PTII/bin/ptolemy -test $PTII/ptolemy/domains/ct/demo/CarTracking/CarTracking.xml 092 // which will open up a large xml file and then close after 2 seconds. 093 if (attributeName.equals("class")) { 094 if (_actorsThatShouldHaveIcons.containsKey(attributeValue)) { 095 // We found a class that needs an _icon 096 _currentlyProcessingActorThatMayNeedAnIcon = true; 097 098 if (container != null) { 099 _currentActorFullName = container.getFullName() + "." 100 + _lastNameSeen; 101 } else { 102 _currentActorFullName = "." + _lastNameSeen; 103 } 104 105 _iconMoML = (String) _actorsThatShouldHaveIcons 106 .get(attributeValue); 107 } else if (_currentlyProcessingActorThatMayNeedAnIcon 108 && container != null 109 && !container.getFullName().equals(_currentActorFullName) 110 && !container.getFullName() 111 .startsWith(_currentActorFullName)) { 112 // We found another class in a different container 113 // while handling a class with port name changes, so 114 _currentlyProcessingActorThatMayNeedAnIcon = false; 115 } 116 } 117 118 return attributeValue; 119 } 120 121 /** Make modifications to the specified container, which is 122 * defined in a MoML element with the specified name. 123 * @param container The object created by this element. 124 * @param elementName The element name. 125 * @param currentCharData The character data, which appears 126 * only in the doc and configure elements 127 * @param xmlFile The file currently being parsed. 128 * @exception Exception if there is a problem substituting 129 * in the new value. 130 * @deprecated Use {@link #filterEndElement(NamedObj, String, StringBuffer, String, MoMLParser)} 131 * instead and pass a MoMLParser. 132 */ 133 @Deprecated 134 @Override 135 public void filterEndElement(NamedObj container, String elementName, 136 StringBuffer currentCharData, String xmlFile) throws Exception { 137 filterEndElement(container, elementName, currentCharData, xmlFile, 138 new MoMLParser()); 139 } 140 141 /** Make modifications to the specified container, which is 142 * defined in a MoML element with the specified name. 143 * @param container The object created by this element. 144 * @param elementName The element name. 145 * @param currentCharData The character data, which appears 146 * only in the doc and configure elements 147 * @param xmlFile The file currently being parsed. 148 * @param parser The parser in which MoML is optionally evaluated. 149 * @exception Exception if there is a problem substituting 150 * in the new value. 151 */ 152 @Override 153 public void filterEndElement(NamedObj container, String elementName, 154 StringBuffer currentCharData, String xmlFile, MoMLParser parser) 155 throws Exception { 156 if (_currentlyProcessingActorThatMayNeedAnIcon 157 && elementName.equals("entity") && container != null 158 && container.getFullName().equals(_currentActorFullName)) { 159 _currentlyProcessingActorThatMayNeedAnIcon = false; 160 161 // Note that setContext() calls reset() so we don't want 162 // to do it on the main parser. 163 parser.setContext(container); 164 165 try { 166 // Do not call parse(_iconMoML) here, since that method 167 // will fail if we are in an applet because it tries 168 // to read user.dir 169 parser.parse(null, _iconMoML); 170 MoMLParser.setModified(true); 171 } catch (Exception ex) { 172 throw new IllegalActionException(null, ex, 173 "Failed to parse\n" + _iconMoML); 174 } 175 } 176 } 177 178 /** Return a string that describes what the filter does. 179 * @return the description of the filter that ends with a newline. 180 */ 181 @Override 182 public String toString() { 183 StringBuffer results = new StringBuffer(getClass().getName() 184 + ": Add specialized icons that display the value\n" 185 + "of one of the parameters.\n" + "The affected actors are:\n"); 186 Iterator actors = _actorsThatShouldHaveIcons.keySet().iterator(); 187 188 while (actors.hasNext()) { 189 results.append("\t" + (String) actors.next() + "\n"); 190 } 191 192 return results.toString(); 193 } 194 195 /////////////////////////////////////////////////////////////////// 196 //// private variables //// 197 // Map of actors that should have _icon 198 private static HashMap _actorsThatShouldHaveIcons; 199 200 // The the full name of the actor we are currently processing 201 private String _currentActorFullName; 202 203 // Set to true if we are currently processing an actor that may 204 // need _icon added, set to false when we are done. 205 private boolean _currentlyProcessingActorThatMayNeedAnIcon = false; 206 207 // The moml that we should substitute in if we need to add 208 // an _icon 209 private String _iconMoML; 210 211 // Last "name" value seen, for use if we see a "class". 212 private String _lastNameSeen; 213 214 static { 215 /////////////////////////////////////////////////////////// 216 // Actors that should have _icon 217 _actorsThatShouldHaveIcons = new HashMap(); 218 219 // In alphabetic order by actor class name. 220 _actorsThatShouldHaveIcons.put("ptolemy.actor.lib.Const", 221 "<property name=\"_icon\" " 222 + "class=\"ptolemy.vergil.icon.BoxedValueIcon\">\n" 223 + "<property name=\"attributeName\" value=\"value\"/>\n" 224 + "<property name=\"displayWidth\" value=\"40\"/>\n" 225 + "</property>\n"); 226 227 // In alphabetic order by actor class name. 228 _actorsThatShouldHaveIcons.put("ptolemy.actor.lib.Expression", 229 "<property name=\"_icon\" " 230 + "class=\"ptolemy.vergil.icon.BoxedValueIcon\">\n" 231 + "<property name=\"attributeName\" value=\"expression\"/>\n" 232 + "<property name=\"displayWidth\" value=\"60\"/>\n" 233 + "</property>\n"); 234 235 String functionIcon = "<property name=\"_icon\" " 236 + "class=\"ptolemy.vergil.icon.AttributeValueIcon\">\n" 237 + "<property name=\"attributeName\" value=\"function\"/>\n" 238 + "</property>\n"; 239 240 _actorsThatShouldHaveIcons.put("ptolemy.actor.lib.MathFunction", 241 functionIcon); 242 243 _actorsThatShouldHaveIcons.put("ptolemy.actor.lib.Scale", 244 "<property name=\"_icon\" " 245 + "class=\"ptolemy.vergil.icon.AttributeValueIcon\">\n" 246 + "<property name=\"attributeName\" value=\"factor\"/>\n" 247 + "</property>\n"); 248 249 _actorsThatShouldHaveIcons.put("ptolemy.actor.lib.TrigFunction", 250 functionIcon); 251 } 252}