001/* A tree model for the Vergil library panel. 002 003 Copyright (c) 2000-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.vergil.tree; 029 030import java.util.Collections; 031import java.util.HashMap; 032import java.util.Iterator; 033import java.util.LinkedList; 034import java.util.List; 035import java.util.Map; 036 037import javax.swing.tree.TreePath; 038 039import ptolemy.kernel.CompositeEntity; 040import ptolemy.kernel.Entity; 041import ptolemy.kernel.util.Attribute; 042import ptolemy.kernel.util.NamedObj; 043import ptolemy.kernel.util.Workspace; 044import ptolemy.moml.EntityLibrary; 045import ptolemy.vergil.icon.EditorIcon; 046 047/////////////////////////////////////////////////////////////////// 048//// VisibleTreeModel 049 050/** 051 052 A tree model for the Vergil library panel. This is a tree model that 053 shows all entities and some ports, relations, and attributes. The ports, 054 relations, and attributes that it shows are those that 055 contain an attribute of class EditorIcon, or that contain an 056 attribute named "_iconDescription" or "_smallIconDescription". 057 A composite entity that contains an attribute with name "_libraryMarker" 058 is treated as a sublibrary. A composite entity without such an attribute 059 is treated as an atomic entity. 060 This is designed for use with JTree, which renders the hierarchy. 061 062 @author Steve Neuendorffer and Edward A. Lee 063 @version $Id$ 064 @since Ptolemy II 1.0 065 @Pt.ProposedRating Red (eal) 066 @Pt.AcceptedRating Red (johnr) 067 */ 068public class VisibleTreeModel extends FullTreeModel { 069 /** Create a new tree model with the specified root. 070 * @param root The root of the tree. 071 */ 072 public VisibleTreeModel(CompositeEntity root) { 073 super(root); 074 _workspace = root.workspace(); 075 _workspaceAttributeVersion = _workspace.getVersion(); 076 } 077 078 /////////////////////////////////////////////////////////////////// 079 //// public methods //// 080 081 /** Return true if the object is a leaf node. An object is a leaf 082 * node if it has no children that are instances of one of the classes 083 * specified by setFilter(), if a filter has been specified. 084 * @param object The object. 085 * @return True if the node has no children. 086 */ 087 @Override 088 public boolean isLeaf(Object object) { 089 // NOTE: handle EntityLibrary specially to prevent evaluation 090 // of the library prematurely. 091 if (object instanceof EntityLibrary) { 092 return false; 093 } 094 095 // If the object is an instance of CompositeEntity, but does not 096 // contain an attribute named "_libraryMarker", then treat it as an 097 // atomic entity. 098 if (object instanceof CompositeEntity) { 099 Attribute marker = ((CompositeEntity) object) 100 .getAttribute("_libraryMarker"); 101 102 if (marker == null) { 103 return true; 104 } 105 } 106 107 // Defer to the parent for the rest. 108 return super.isLeaf(object); 109 } 110 111 /** Override the base class to do nothing. This seems risky, but 112 * the problem is that without it, every time you expand a library 113 * that has a image or PDF icon it, the entire library collapses, 114 * which is extremely annoying. I guess this is OK under the 115 * assumption that the library does not change during execution. 116 * @param path The path of the node that has changed. 117 * @param newValue The new value of the node. 118 */ 119 @Override 120 public void valueForPathChanged(TreePath path, Object newValue) { 121 // Do nothing. 122 } 123 124 /////////////////////////////////////////////////////////////////// 125 //// protected methods //// 126 127 /** Return the list of attributes, or an empty list if there are none. 128 * Override this method if you wish to show only a subset of the 129 * attributes. 130 * @param object The object. 131 * @return A list of attributes. 132 */ 133 @Override 134 protected List _attributes(Object object) { 135 if (!(object instanceof NamedObj)) { 136 return Collections.EMPTY_LIST; 137 } 138 139 // Use the cached list, if possible. 140 long version = _workspace.getVersion(); 141 142 if (version == _workspaceAttributeVersion) { 143 Object result = _attributeListCache.get(object); 144 145 if (result != null) { 146 return (List) result; 147 } 148 } 149 150 // Cache is not valid. 151 List result = new LinkedList(); 152 Iterator attributes = ((NamedObj) object).attributeList().iterator(); 153 154 while (attributes.hasNext()) { 155 NamedObj attribute = (NamedObj) attributes.next(); 156 157 if (_isVisible(attribute)) { 158 result.add(attribute); 159 } 160 } 161 162 _attributeListCache.put(object, result); 163 _workspaceAttributeVersion = _workspace.getVersion(); 164 return result; 165 } 166 167 /** Return true if the object contains either an attribute of 168 * class EditorIcon or an attribute of any class named 169 * "_iconDescription" or "_smallIconDescription". This 170 * will result in the object being rendered in the library. 171 * @param object The object. 172 * @return True if the object is to be rendered in the library. 173 */ 174 protected boolean _isVisible(NamedObj object) { 175 List iconList = object.attributeList(EditorIcon.class); 176 177 if (iconList.size() > 0 178 || object.getAttribute("_iconDescription") != null 179 || object.getAttribute("_smallIconDescription") != null) { 180 return true; 181 } else { 182 return false; 183 } 184 } 185 186 /** Return the list of ports, or an empty list if there are none. 187 * Override this method if you wish to show only a subset of the 188 * ports. 189 * @param object The object. 190 * @return A list of ports. 191 */ 192 @Override 193 protected List _ports(Object object) { 194 if (!(object instanceof Entity)) { 195 return Collections.EMPTY_LIST; 196 } 197 198 // Use the cached list, if possible. 199 long version = _workspace.getVersion(); 200 201 if (version == _workspacePortVersion) { 202 Object result = _portListCache.get(object); 203 204 if (result != null) { 205 return (List) result; 206 } 207 } 208 209 // Cache is not valid. 210 List result = new LinkedList(); 211 Iterator ports = ((Entity) object).portList().iterator(); 212 213 while (ports.hasNext()) { 214 NamedObj port = (NamedObj) ports.next(); 215 216 if (_isVisible(port)) { 217 result.add(port); 218 } 219 } 220 221 _portListCache.put(object, result); 222 _workspacePortVersion = _workspace.getVersion(); 223 return result; 224 } 225 226 /** Return the list of relations, or an empty list if there are none. 227 * Override this method if you wish to show only a subset of the 228 * relations. 229 * @param object The object. 230 * @return A list of relations. 231 */ 232 @Override 233 protected List _relations(Object object) { 234 if (!(object instanceof CompositeEntity)) { 235 return Collections.EMPTY_LIST; 236 } 237 238 // Use the cached list, if possible. 239 long version = _workspace.getVersion(); 240 241 if (version == _workspaceRelationVersion) { 242 Object result = _relationListCache.get(object); 243 244 if (result != null) { 245 return (List) result; 246 } 247 } 248 249 // Cache is not valid. 250 List result = new LinkedList(); 251 Iterator relations = ((CompositeEntity) object).relationList() 252 .iterator(); 253 254 while (relations.hasNext()) { 255 NamedObj relation = (NamedObj) relations.next(); 256 257 if (_isVisible(relation)) { 258 result.add(relation); 259 } 260 } 261 262 _relationListCache.put(object, result); 263 _workspaceRelationVersion = _workspace.getVersion(); 264 return result; 265 } 266 267 /////////////////////////////////////////////////////////////////// 268 //// private variables //// 269 // Workspace and version information. 270 private Workspace _workspace; 271 272 private long _workspaceAttributeVersion; 273 274 private long _workspacePortVersion; 275 276 private long _workspaceRelationVersion; 277 278 // Cache for visible attributes. 279 private Map _attributeListCache = new HashMap(); 280 281 // Cache for visible ports. 282 private Map _portListCache = new HashMap(); 283 284 // Cache for visible relations. 285 private Map _relationListCache = new HashMap(); 286}