001    /*
002      Copyright (C) 2002-2003 Laurent Martelli <laurent@aopsys.com>
003      
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful, but
010      WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012      Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.aspects.gui.web;
020    
021    import org.objectweb.jac.aspects.gui.*;
022    import org.objectweb.jac.core.Wrappee;
023    import org.objectweb.jac.core.rtti.CollectionItem;
024    import java.io.PrintWriter;
025    import java.util.HashSet;
026    
027    /**
028     * This class defines a Swing component tree view for objects that are
029     * related to a root object through relations or collections.
030     *
031     * @see GuiAC */
032    
033    public class Tree extends AbstractView
034        implements View, HTMLViewer, TreeListener
035    {
036        TreeModel model;
037        boolean showRelations = true;
038        RootNode rootNode = null;
039        HashSet expandedNodes = new HashSet();
040    
041        /**
042         * Constructs a new tree view.
043         * @param pathDef designate root objects of the tree
044         * @param showRelations wether to build a node for relation items
045         */
046        public Tree(ViewFactory factory, DisplayContext context,
047                    String pathDef, boolean showRelations) {
048            super(factory,context);
049            this.showRelations = showRelations;
050    
051            rootNode = new RootNode();
052            model = new TreeModel( rootNode, pathDef, showRelations );
053        }
054        // interface TreeView
055    
056        public void close(boolean validate) {
057            model.unregisterEvents();
058        }
059    
060        public void genHTML(PrintWriter out) {
061            genNode(out,(AbstractNode)model.getRoot(),"");
062        }
063    
064        protected boolean isExpanded(AbstractNode node) {
065            return expandedNodes.contains(node);
066        }
067    
068        protected void genNode(PrintWriter out, AbstractNode node, String curPath) {
069            String nodePath = node instanceof RootNode ? "/" : curPath;
070            String nodeClass = node.isLeaf() ? "leafNode" : "treeNode";
071            boolean isRoot = node == model.getRoot();
072    
073            if (!isRoot) {
074                out.println("<div class=\""+nodeClass+"\">");
075                if (!node.isLeaf()) {
076                    if (isExpanded(node)) 
077                        out.print("  <a href=\""+eventURL("onCollapseNode")+
078                                  "&nodePath="+nodePath+"\" class=\"fixed\">[-]</a>");
079                    else 
080                        out.print("  <a href=\""+eventURL("onExpandNode")+
081                                  "&nodePath="+nodePath+"\" class=\"fixed\">[+]</a>");
082                }
083                out.println(iconElement(node.getIcon(),"")+
084                            " <a href=\""+eventURL("onSelectNode")+"&nodePath="+
085                            nodePath+"\">"+node.getText()+"</a>");
086            }
087    
088            if (isExpanded(node) || isRoot) {
089                out.println("  <div class=\""+(isRoot?"rootNodes":"nodes")+"\">");
090                for (int i=0; i<node.getChildCount();i++) {
091                    genNode(out,(AbstractNode)node.getChildAt(i),curPath+"/"+i);
092                }
093                out.println("  </div>");
094            }
095            if (!isRoot) {
096                out.println("</div>");
097            }
098        }
099    
100        // TreeListener interface
101    
102        public void onSelectNode(String nodePath) {
103            try {
104                AbstractNode node = pathToNode(nodePath);
105                logger.debug("onSelectNode path="+nodePath+" -> "+node);
106                if (node == null) 
107                    return;
108                logger.debug("  node="+node);
109                Object selected = node.getUserObject();
110                logger.debug("  selected="+selected);
111                if (selected instanceof CollectionItem) {
112                    context.getDisplay().refresh();
113                } else {
114                    EventHandler.get().onNodeSelection(context,node,true);
115                }
116            } catch (Exception e) {
117                context.getDisplay().showError("Error",e.toString());
118            }
119        }
120    
121        public void onExpandNode(String nodePath) {
122            try {
123                AbstractNode node = pathToNode(nodePath);
124                // ensure that the children of this node are uptodate
125                if (node instanceof ObjectNode)
126                    ((ObjectNode)node).updateChildren();
127                expandedNodes.add(node);
128            } finally {
129                context.getDisplay().refresh();
130            }
131        }
132    
133        public void onCollapseNode(String nodePath) {
134            try {
135                AbstractNode node = pathToNode(nodePath);
136                expandedNodes.remove(node);
137            } finally {
138                context.getDisplay().refresh();
139            }
140        }
141    
142        /*
143         * Get a Node from its path. 
144         */
145        protected AbstractNode pathToNode(String nodePath) {
146            AbstractNode node = (AbstractNode)model.getRoot();
147            if (nodePath.startsWith("/")) {
148                nodePath = nodePath.substring(1);
149                int index = nodePath.indexOf("/");
150                while (index!=-1) {
151                    node = (AbstractNode)node.getChildAt(
152                        Integer.parseInt(nodePath.substring(0,index)));
153                    nodePath = nodePath.substring(index+1);
154                    index = nodePath.indexOf("/");
155                } 
156                if (nodePath.length()>0)
157                    node = (AbstractNode)node.getChildAt(Integer.parseInt(nodePath));
158            }
159            return node;
160        }
161    }