001/* Action to remove a custom icon. 002 003 Copyright (c) 2003-2016 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.vergil.toolbox; 029 030import java.awt.event.ActionEvent; 031import java.net.URL; 032import java.util.Iterator; 033import java.util.List; 034 035import ptolemy.actor.gui.Configuration; 036import ptolemy.gui.Top; 037import ptolemy.kernel.util.Attribute; 038import ptolemy.kernel.util.ChangeRequest; 039import ptolemy.kernel.util.NamedObj; 040import ptolemy.moml.IconLoader; 041import ptolemy.moml.MoMLParser; 042import ptolemy.util.FileUtilities; 043import ptolemy.vergil.icon.EditorIcon; 044import ptolemy.vergil.icon.XMLIcon; 045 046/////////////////////////////////////////////////////////////////// 047//// ConfigureAction 048 049/** Action to remove a custom icon. 050 @author Edward A. Lee 051 @version $Id$ 052 @since Ptolemy II 4.0 053 @Pt.ProposedRating Red (eal) 054 @Pt.AcceptedRating Red (johnr) 055 */ 056@SuppressWarnings("serial") 057public class RemoveIconAction extends FigureAction { 058 public RemoveIconAction() { 059 super("Remove Custom Icon"); 060 } 061 062 /////////////////////////////////////////////////////////////////// 063 //// public methods //// 064 065 /** Process the remove icon command. 066 * @param e The event. 067 */ 068 @Override 069 public void actionPerformed(ActionEvent e) { 070 // Determine which entity was selected for the look inside action. 071 super.actionPerformed(e); 072 073 final NamedObj object = getTarget(); 074 075 // If the source of the event was a button, then super.actionPerformed(e) 076 // will return null. There are other reasons super.actionPerformed(e) 077 // will return null as well. 078 if (object != null) { 079 // In theory, there should be only one. 080 // But just in case, we remove all. 081 Iterator icons = object.attributeList(EditorIcon.class).iterator(); 082 083 while (icons.hasNext()) { 084 EditorIcon icon = (EditorIcon) icons.next(); 085 086 // An XMLIcon is not a custom icon, so don't remove it. 087 if (!(icon instanceof XMLIcon)) { 088 final String iconName = icon.getName(); 089 // FIXME: No undo! 090 ChangeRequest request = new ChangeRequest(this, 091 "Remove Custom Icon") { 092 @Override 093 protected void _execute() throws Exception { 094 Attribute attribute = object.getAttribute(iconName); 095 if (attribute != null) { 096 attribute.setContainer(null); 097 } 098 // Restore the default icon. 099 // FIXME: Could be an XML icon. 100 Runnable runnable = new Runnable() { 101 @Override 102 public void run() { 103 IconLoader iconLoader = MoMLParser 104 .getIconLoader(); 105 String className = object.getClassName(); 106 if (iconLoader != null) { 107 try { 108 iconLoader.loadIconForClass( 109 className, object); 110 } catch (Exception e) { 111 // Ignore. Not much we can do here anyway. 112 System.err.println( 113 "WARNING: Failed to load icon for class " 114 + className + ": " 115 + e); 116 } 117 } else { 118 // This is similar to MoMLParser._loadIconForClass, but 119 // it seems there is no way to reuse that here. 120 String fileName = "$CLASSPATH/" 121 + className.replace('.', '/') 122 + "Icon.xml"; 123 MoMLParser newParser = new MoMLParser( 124 object.workspace()); 125 newParser.setContext(object); 126 // Initiate tracking of objects created during the parse. 127 newParser.clearTopObjectsList(); 128 try { 129 URL url = FileUtilities.nameToURL( 130 fileName, null, 131 object.getClass() 132 .getClassLoader()); 133 newParser.parse(url, url); 134 // Have to mark the contents derived objects, so that 135 // the icon is not exported with the MoML export. 136 List<NamedObj> icons = newParser 137 .topObjectsCreated(); 138 if (icons != null) { 139 Iterator objects = icons 140 .iterator(); 141 142 while (objects.hasNext()) { 143 NamedObj newObject = (NamedObj) objects 144 .next(); 145 newObject 146 .setDerivedLevel(1); 147 _markContentsDerived( 148 newObject, 1); 149 } 150 } 151 } catch (Exception e) { 152 // Ignore. Not much we can do here anyway. 153 System.err.println( 154 "WARNING: Failed to load icon for class " 155 + className + ": " 156 + e); 157 } 158 } 159 } 160 }; 161 Top.deferIfNecessary(runnable); 162 } 163 }; 164 object.requestChange(request); 165 } 166 } 167 } 168 } 169 170 /** Specify the configuration. 171 * In this action, this method does nothing. 172 * @param configuration The configuration. 173 */ 174 public void setConfiguration(Configuration configuration) { 175 // Do nothing. 176 } 177 178 /////////////////////////////////////////////////////////////////// 179 //// private methods //// 180 181 // NOTE: The following method is largely duplicated from MoMLParser, 182 // but exposing that method is not a good idea. 183 184 /** Mark the contents as being derived objects at a depth 185 * one greater than the depth argument, and then recursively 186 * mark their contents derived. 187 * This makes them not export MoML, and prohibits name and 188 * container changes. Normally, the argument is an Entity, 189 * but this method will accept any NamedObj. 190 * This method also adds all (deeply) contained instances 191 * of Settable to the _paramsToParse list, which ensures 192 * that they will be validated. 193 * @param object The instance that is defined by a class. 194 * @param depth The depth (normally 0). 195 */ 196 private void _markContentsDerived(NamedObj object, int depth) { 197 // NOTE: It is necessary to mark objects deeply contained 198 // so that we can disable deletion and name changes. 199 // While we are at it, we add any 200 // deeply contained Settables to the _paramsToParse list. 201 Iterator objects = object.lazyContainedObjectsIterator(); 202 203 while (objects.hasNext()) { 204 NamedObj containedObject = (NamedObj) objects.next(); 205 containedObject.setDerivedLevel(depth + 1); 206 _markContentsDerived(containedObject, depth + 1); 207 } 208 } 209}