001 /* 002 Copyright (C) 2002-2003 Renaud Pawlak <renaud@aopsys.com>, 003 Laurent Martelli <laurent@aopsys.com> 004 005 This program is free software; you can redistribute it and/or modify 006 it under the terms of the GNU Lesser General Public License as 007 published by the Free Software Foundation; either version 2 of the 008 License, or (at your option) any later version. 009 010 This program is distributed in the hope that it will be useful, but 011 WITHOUT ANY WARRANTY; without even the implied warranty of 012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 Lesser General Public License for more details. 014 015 You should have received a copy of the GNU Lesser General Public 016 License along with this program; if not, write to the Free Software 017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 018 USA */ 019 020 package org.objectweb.jac.aspects.gui; 021 022 import java.util.Arrays; 023 import java.util.Collection; 024 import java.util.Iterator; 025 import java.util.Vector; 026 import javax.swing.event.TreeSelectionEvent; 027 import javax.swing.tree.DefaultTreeModel; 028 import javax.swing.tree.TreePath; 029 import org.apache.log4j.Logger; 030 import org.objectweb.jac.core.NameRepository; 031 import org.objectweb.jac.core.rtti.ClassItem; 032 import org.objectweb.jac.core.rtti.ClassRepository; 033 import org.objectweb.jac.core.rtti.CollectionItem; 034 import org.objectweb.jac.core.rtti.FieldItem; 035 import org.objectweb.jac.core.rtti.MetaItem; 036 037 /** 038 * A data model for trees. 039 */ 040 041 public class TreeModel extends DefaultTreeModel implements TreeView { 042 static Logger logger = Logger.getLogger("gui.treeview"); 043 static Logger loggerPerf = Logger.getLogger("perf"); 044 045 Vector treeObjects = new Vector(); 046 Vector treeNodes = new Vector(); 047 boolean showRelations; 048 String rootObjects; 049 050 /** 051 * Constructs a new tree model. 052 * 053 * @param rootNode the root node 054 * @param rootObjects ??? 055 * @param showRelations tells if the tree should show the 056 * interobjects relations as nodes */ 057 public TreeModel(RootNode rootNode, 058 String rootObjects, boolean showRelations) { 059 super(rootNode); 060 this.showRelations = showRelations; 061 this.rootObjects = rootObjects; 062 rootNode.setModel(this); 063 initTree(this,rootObjects,showRelations); 064 } 065 066 public void setRootNode(AbstractNode root) { 067 setRoot(root); 068 } 069 070 public void addNode(AbstractNode parent, AbstractNode child) { 071 logger.debug("addNode "+child+" to "+parent); 072 parent.add(child); 073 } 074 075 public void setSelection(TreePath selection) { 076 Object[] listeners = listenerList.getListenerList(); 077 TreeSelectionEvent e = null; 078 // Process the listeners last to first, notifying 079 // those that are interested in this event 080 for (int i = listeners.length-2; i>=0; i-=2) { 081 if (listeners[i]==TreeListener.class) { 082 // Lazily create the event: 083 ((TreeListener)listeners[i+1]).setSelection(selection); 084 } 085 } 086 } 087 088 public void addTreeListener(TreeListener listener) { 089 listenerList.add(TreeListener.class,listener); 090 } 091 092 public void unregisterEvents() { 093 Iterator i = treeNodes.iterator(); 094 while (i.hasNext()) { 095 AbstractNode node = (AbstractNode)i.next(); 096 node.unregisterEvents(); 097 } 098 } 099 100 /** 101 * Add the children nodes for a node. 102 * 103 * @param rootNode the parent node for which to add children nodes. 104 * @param o the object represented by the rootNode 105 */ 106 public static void addNodes(TreeView tree, ObjectNode rootNode, 107 Object o, boolean showRelations) { 108 logger.debug("addNodes("+rootNode+","+o+", showRelations="+showRelations+")..."); 109 if (o==null) 110 return; 111 long start = System.currentTimeMillis(); 112 // iterates on all the relations 113 ClassItem cli = ClassRepository.get().getClass(o); 114 FieldItem[] rels = (FieldItem[])cli.getAttribute(GuiAC.TREE_ATTRIBUTES_ORDER); 115 Collection related = null; 116 rootNode.setChildrenUptodate(true); 117 if (rels==null) 118 return; 119 for (int itRel=0; itRel<rels.length; itRel++) { 120 FieldItem rel = rels[itRel]; 121 if (!GuiAC.isVisible(o,(MetaItem)rel)) 122 continue; 123 if (rel instanceof CollectionItem) { 124 CollectionItem collection = (CollectionItem)rel; 125 Collection cRel = collection.getActualCollectionThroughAccessor(o); 126 related = cRel; 127 128 if (showRelations && 129 collection.getAttribute(GuiAC.HIDDEN_TREE_RELATION)==null) { 130 // add a collection node 131 RelationNode relationNode = 132 new RelationNode(tree,o,collection); 133 logger.debug("adding relation node for collection "+collection.getName()); 134 Utils.registerCollection(o,collection,relationNode); 135 rootNode.add(relationNode); 136 Iterator it = related.iterator(); 137 while (it.hasNext()) { 138 Object newObject = it.next(); 139 ObjectNode newNode = new ObjectNode(tree,newObject,o,collection,showRelations); 140 newNode.setLeaf(isLeafNode(tree,newNode,o,showRelations)); 141 relationNode.add(newNode); 142 } 143 } else { 144 logger.debug("adding nodes for collection "+collection.getName()+": "+ 145 Arrays.asList(related.toArray())); 146 Utils.registerCollection(o,collection,rootNode); 147 // recursively add nodes 148 Iterator it = related.iterator(); 149 while (it.hasNext()) { 150 Object newObject = it.next(); 151 logger.debug("adding node for collection "+ 152 collection.getName()+": "+newObject); 153 ObjectNode newNode = new ObjectNode(tree,newObject,o,collection,showRelations); 154 newNode.setLeaf(isLeafNode(tree,newNode,newObject,showRelations)); 155 rootNode.addNode(newNode); 156 } 157 } 158 } else if (rel instanceof FieldItem) { 159 if (showRelations && 160 rel.getAttribute(GuiAC.HIDDEN_TREE_RELATION)==null) 161 { 162 RelationNode relationNode = 163 new RelationNode(tree,o,rel); 164 rootNode.add(relationNode); 165 Object relatedObject = rel.getThroughAccessor(o); 166 if (relatedObject!=null) { 167 ObjectNode newNode = new ObjectNode(tree,relatedObject,o,rel,showRelations); 168 newNode.setLeaf(isLeafNode(tree,newNode,relatedObject,showRelations)); 169 relationNode.add(newNode); 170 } 171 } else { 172 Object relatedObject = rel.getThroughAccessor(o); 173 if (relatedObject!=null) { 174 ObjectNode newNode = new ObjectNode(tree,relatedObject,o,rel,showRelations); 175 newNode.setLeaf(isLeafNode(tree,newNode,relatedObject,showRelations)); 176 rootNode.addNode(newNode); 177 } 178 } 179 } 180 } 181 loggerPerf.info("Added nodes in "+(System.currentTimeMillis()-start)+"ms"); 182 } 183 184 185 /** 186 * Tells wether a node is a leaf or not, without computing all its 187 * children. 188 * 189 * @param tree The tree the node belongs to 190 * @param node the node 191 * @param o the object represented by the node 192 * @param showRelations wether to show a node for relations 193 */ 194 public static boolean isLeafNode(TreeView tree, ObjectNode node, 195 Object o, boolean showRelations) { 196 if (o==null) 197 return true; 198 // iterates on all the relations 199 ClassItem cli = ClassRepository.get().getClass(o); 200 FieldItem[] rels = (FieldItem[])cli.getAttribute(GuiAC.TREE_ATTRIBUTES_ORDER); 201 Collection related = null; 202 boolean isLeaf=true; 203 if (rels==null) 204 return true; 205 for (int itRel=0; itRel<rels.length; itRel++) { 206 FieldItem rel = rels[itRel]; 207 if (!GuiAC.isVisible(o,(MetaItem)rel)) 208 continue; 209 if (rel instanceof CollectionItem) { 210 CollectionItem collection = (CollectionItem)rel; 211 Utils.registerCollection(o,collection,node); 212 if (isLeaf && 213 !collection.getActualCollectionThroughAccessor(o).isEmpty()) { 214 // !! we must not return here because the loop is also used 215 // to register for updates (note that this should be done in 216 // addNodes) 217 isLeaf=false; 218 } 219 } else { 220 Utils.registerField(o,rel,node); 221 if (isLeaf && rel.getThroughAccessor(o)!=null) { 222 isLeaf=false; 223 } 224 } 225 } 226 return isLeaf; 227 } 228 229 /** 230 * Initialize a tree view. 231 * @param tree the tree view to initialize 232 * @param rootObjects a regular expression designating root objects 233 * @param showRelations wether to build nodes for the relations themselves 234 */ 235 public static void initTree(TreeView tree, String rootObjects, 236 boolean showRelations) { 237 logger.debug("initTree "+rootObjects+"..."); 238 239 // the first accessible collection 240 AbstractNode rootNode = new RootNode(); 241 tree.setRootNode(rootNode); 242 Iterator it = NameRepository.getObjects(rootObjects).iterator(); 243 while (it.hasNext()) { 244 Object object = it.next(); 245 ObjectNode objectNode = new ObjectNode(tree,object,null,null,showRelations); 246 rootNode.add(objectNode); 247 objectNode.setLeaf(isLeafNode(tree,objectNode,object,showRelations)); 248 } 249 250 logger.debug("initTree "+rootObjects+" DONE"); 251 } 252 253 }