KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > fr > improve > struts > taglib > layout > treeview > TreeViewTag


1 package fr.improve.struts.taglib.layout.treeview;
2
3 import java.io.Serializable JavaDoc;
4 import java.util.Arrays JavaDoc;
5 import java.util.Hashtable JavaDoc;
6 import java.util.Vector JavaDoc;
7
8 import javax.servlet.ServletContext JavaDoc;
9 import javax.servlet.http.Cookie JavaDoc;
10 import javax.servlet.http.HttpServletRequest JavaDoc;
11 import javax.servlet.jsp.JspException JavaDoc;
12
13 import fr.improve.struts.taglib.layout.PanelTag;
14 import fr.improve.struts.taglib.layout.menu.MenuComponent;
15 import fr.improve.struts.taglib.layout.skin.Skin;
16 import fr.improve.struts.taglib.layout.util.LayoutUtils;
17 import fr.improve.struts.taglib.layout.util.MenuInterface;
18 import fr.improve.struts.taglib.layout.util.TagUtils;
19 import fr.improve.struts.taglib.layout.util.TreeviewInterface;
20
21 /**
22  * Display a treeview.
23  *
24  * If the treeview is defined from <layout:menuItem> tags it is totally loaded and nodes are open and close by javascript.<br>
25  * <br>
26  * If the treeview is defined from the menu repository, only the root nodes are loaded.
27  * Nested nodes are loaded one time when the user open them.
28  * This allows for very big treeview without having to send a lot of data at a time.
29  *
30  * Compatible with Scott Sayles menu framework.
31  * @author: Jean-Noël Ribette
32  */

33 public class TreeViewTag extends PanelTag implements MenuInterface {
34
35     /**
36      * Key used to store the treeview ids in the session.
37      */

38     private static final String JavaDoc TREEVIEW_NUMBER = "fr.improve.struts.taglib.layout.TreeviewTag.TREEVIEW_NUMBER";
39     
40     /**
41      * Default treeview action url
42      */

43     public static final String JavaDoc DEFAULT_TREEVIEW_ACTION = "treeview.do";
44     
45     /**
46      * Useful structure storing the ids of the known treeview.
47      *
48      * Ids of named treeview defined in the menu repository are stored in the namedTreeview map.
49      *
50      * Ids of treeview defined with menuitem tags are stored in the anonymousTreeview map
51      * and are associated with the request URI.
52      * This makes it impossible to have two anonymous treeview in the same request.
53      */

54     public class TreeViewIds implements Serializable JavaDoc {
55         private int counter = -1;
56         java.util.Hashtable JavaDoc namedTreeview;
57         java.util.Hashtable JavaDoc anonymousTreeview;
58         TreeViewIds() {
59             namedTreeview = new Hashtable JavaDoc();
60             anonymousTreeview = new Hashtable JavaDoc();
61         }
62         public synchronized int getNewId() {
63             counter++;
64             return counter;
65         }
66     }
67
68     /**
69      * The content of the treeview.
70      */

71     protected Vector JavaDoc menus = new Vector JavaDoc();
72     
73     /**
74      * True if the styleClass should be subfixed with the node depth.
75      */

76     protected boolean autoIncrement = true;
77     
78     /**
79      * Specify the number of levels.
80      */

81     protected int expandedLevelsAtFirst = -1;
82     
83     /**
84      * If there are nested &lt;layout:menuItem&gt; tags, those tags will call this methods to add items to the treeview.
85      */

86     public void addItem(MenuComponent item) {
87         menus.add(item);
88     }
89     public void addItems(MenuComponent[] items) {
90         menus.addAll(Arrays.asList(items));
91     }
92     
93 /**
94  * End the tag and display the treeview.
95  */

96 public int doEndLayoutTag() throws JspException JavaDoc {
97     // Get the menu from the menu repository if the menuItem tag is not used.
98
// menuItem tags CAN be used WITH menu attributs specified (this doesn't allow
99
// to use indirection, but allows to use cookie to store treeview state).
100
boolean allowIndirection = false;
101     if (menus.size()==0 && name!=null) {
102         MenuComponent lc_tree = LayoutUtils.getMenu(pageContext, name);
103         if (lc_tree==null) {
104             throw new JspException JavaDoc("Could not find menu named \"" + name + "\"");
105         }
106         addItems(lc_tree.getMenuComponents());
107         allowIndirection = true;
108     }
109     
110     doStartLayout();
111     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
112     doStartPanel(buffer);
113     
114     buffer.append("<tr><td>");
115     
116     // Get the treeview id.
117
String JavaDoc lc_i = computeTreeviewId();
118     
119     buffer.append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\" id=\"treeView" + lc_i+ "\">\n");
120     
121     // Compute the styleClass name.
122
String JavaDoc lc_styleClass = styleClass;
123     if (lc_styleClass==null) {
124         lc_styleClass = "";
125     }
126     if (lc_styleClass.length()!=0 && autoIncrement) {
127         lc_styleClass += "1";
128     }
129
130     // Generate the treeview content
131
doPrintMenu(buffer,(MenuComponent[])menus.toArray(new MenuComponent[menus.size()]), (HttpServletRequest JavaDoc)pageContext.getRequest(), pageContext.getServletContext(), bundle, lc_i, name, lc_styleClass, allowIndirection);
132     
133     buffer.append("</table>");
134     
135     // If we are using indirection, generates an hidden frame.
136
if (pageContext.getRequest().getAttribute("fr.improve.struts.taglib.layout.treeview.TreeViewTag.KEY")==null && name!=null && allowIndirection) {
137         buffer.append("<iframe id=\"treeFrame\" name=\"treeFrame\" style=\"width:0px; height:0px; border: 0px\" SRC=\"");
138         buffer.append(buildIFrameSource((HttpServletRequest JavaDoc)pageContext.getRequest()));
139         buffer.append("\"></iframe>");
140         pageContext.getRequest().setAttribute("fr.improve.struts.taglib.layout.treeview.TreeViewTag.KEY", "");
141     }
142     
143     buffer.append("</td></tr>");
144     doEndPanel(buffer);
145     
146     if (expandedLevelsAtFirst > 0) {
147         // the user wants to have the tree expanded the first time it is generated
148
Cookie JavaDoc[] lc_cookies = ((HttpServletRequest JavaDoc) pageContext.getRequest()).getCookies();
149         boolean lc_firstDisplay = true;
150         if (lc_cookies != null) {
151             for (int i = 0; i < lc_cookies.length; i++)
152             {
153                 if (lc_cookies[i].getName().equals("treeView")) {
154                     // a cookie is stored: that means this is not the first rendering
155
lc_firstDisplay = false;
156                     break;
157                 }
158             }
159         }
160         if (lc_firstDisplay) {
161             buffer.append("<script>");
162             buffer.append("expandFirstLevels(\"");
163             buffer.append(lc_i);
164             buffer.append("\", ");
165             buffer.append(expandedLevelsAtFirst);
166             buffer.append(");");
167             buffer.append("</script>");
168         }
169     }
170     
171     TagUtils.write(pageContext, buffer.toString());
172     doEndLayout();
173
174     menus.removeAllElements();
175     name = null;
176     return EVAL_PAGE;
177 }
178
179     /**
180      * Compute the id of the treeview.
181      * Treeview ids are integers starting from 0.
182      */

183     private String JavaDoc computeTreeviewId() throws JspException JavaDoc {
184         if (name!=null) {
185             return name;
186         }
187         TreeViewIds treeviewIds = (TreeViewIds) pageContext.getSession().getAttribute(TREEVIEW_NUMBER);
188         Integer JavaDoc lc_id;
189         if (treeviewIds == null) {
190             treeviewIds = new TreeViewIds();
191             pageContext.getSession().setAttribute(TREEVIEW_NUMBER, treeviewIds);
192         }
193         if (name!=null) {
194             lc_id = (Integer JavaDoc) treeviewIds.namedTreeview.get(name);
195             if (lc_id==null) {
196                 lc_id = new Integer JavaDoc(treeviewIds.getNewId());
197                 treeviewIds.namedTreeview.put(name, lc_id);
198             }
199             return lc_id.toString();
200         } else {
201             if (pageContext.getRequest().getAttribute(TREEVIEW_NUMBER)!=null) {
202                 throw new JspException JavaDoc("There can be only one anonymous treeview per request");
203             } else {
204                 pageContext.getRequest().setAttribute(TREEVIEW_NUMBER, "");
205                 lc_id = (Integer JavaDoc) treeviewIds.anonymousTreeview.get(((HttpServletRequest JavaDoc)pageContext.getRequest()).getRequestURI());
206                 if (lc_id==null) {
207                     lc_id = new Integer JavaDoc(treeviewIds.getNewId());
208                     treeviewIds.anonymousTreeview.put(((HttpServletRequest JavaDoc)pageContext.getRequest()).getRequestURI(), lc_id);
209                 }
210                 return lc_id.toString();
211             }
212         }
213     }
214     
215     public static int doPrintMenu(StringBuffer JavaDoc buffer, MenuComponent[] menus, HttpServletRequest JavaDoc in_request, ServletContext JavaDoc in_servletcontext, String JavaDoc in_bundle, String JavaDoc in_path, String JavaDoc in_name, String JavaDoc in_styleClass) throws JspException JavaDoc {
216         return doPrintMenu(buffer, menus, in_request, in_servletcontext, in_bundle, in_path, in_name, in_styleClass, true);
217     }
218
219     /**
220      * Print the given menus.
221      *
222      * @param buffer StringBuffer in which the HTML code is generated
223      * @param menus The menus do display
224      * @param in_request The current request
225      * @param in_servletContext The context of the servlet (in which is the application message resources).
226      * @param in_bundle Name of the message resources to use.
227      * @param in_path The nested menus path
228      * @param in_name Name of the menu if taken from the menu repository
229      *
230      * @return The number of items generated.
231      */

232     public static int doPrintMenu(StringBuffer JavaDoc buffer, MenuComponent[] menus, HttpServletRequest JavaDoc in_request, ServletContext JavaDoc in_servletcontext, String JavaDoc in_bundle, String JavaDoc in_path, String JavaDoc in_name, String JavaDoc in_styleClass, boolean in_allowIndirection) throws JspException JavaDoc {
233         // Get a treeview renderer.
234
TreeviewInterface lc_treeviewRenderer = LayoutUtils.getSkin(in_request.getSession()).getTreeviewInterface();
235         
236         // init the info.
237
TreeItemInfo lc_info = new TreeItemInfo();
238         
239         int lc_numberOfMenusPrinted = menus.length;
240
241         // Get the images directory.
242
lc_info.imageDirectory = LayoutUtils.getSkin(in_request.getSession()).getImageDirectory(in_request);
243
244         // Compute the styleClass.
245
lc_info.styleClass = lc_treeviewRenderer.computeStyleClass(in_styleClass);
246         
247         lc_info.bundle = in_bundle;
248         lc_info.name = in_name;
249         
250         // Render each item.
251
for (int i=0;i<menus.length;i++) {
252             
253             // ------------------- initialize the iteration -------------- //
254

255             
256             // Get the current item.
257
MenuComponent item = (MenuComponent) menus[i];
258             String JavaDoc link = item.getLocation();
259             String JavaDoc key = item.getTitle();
260             String JavaDoc image = item.getImage();
261             String JavaDoc target = item.getTarget();
262             String JavaDoc onclick = item.getOnClick();
263             String JavaDoc style = item.getStyle();
264             
265             // Are there submenus ?
266
lc_info.hasSubMenus = item.hasMenuComponents();
267             
268             // Is this the last iteration ?
269
lc_info.isLast = i+1 == menus.length;
270             
271             // Compute the path of the current item.
272
// If the item has an id, use it, else use the item position.
273
String JavaDoc lc_id = item.getId();
274             if (lc_id==null) {
275                 lc_id = String.valueOf(i);
276             }
277             lc_info.path = in_path.length()==0 ? lc_id : in_path + "*" + lc_id;
278             
279             // Is the current item open or closed ?
280
lc_info.isClosed = TreeViewTag.isNodeClosed(in_request, lc_info.path);
281             
282             // What is the number of items to render at once in the HTML code ?
283
int lc_numberOfMenusToLoad = LayoutUtils.getSkin(in_request.getSession()).getNumberOfMenusLoaded();
284             
285             // Should all items be rendered at once in the HTML code ?
286
lc_info.useIndirection = in_allowIndirection && lc_numberOfMenusPrinted >= lc_numberOfMenusToLoad && in_name!=null && lc_info.isClosed;
287             
288                     
289             
290             // ------------------- do some real stuff now ----------------- //
291

292             // Start a row.
293
lc_treeviewRenderer.startRow(buffer);
294             
295             // Render a first cell containing the tree image.
296
lc_treeviewRenderer.renderTree(buffer, in_request, lc_info);
297
298             // Start a submenu if there is one.
299
if (lc_info.hasSubMenus) {
300                 lc_treeviewRenderer.startSubMenu(buffer);
301             }
302
303             // Render an icon.
304
lc_treeviewRenderer.renderIcon(buffer, lc_info, item);
305             
306             // Start the label TD.
307
lc_treeviewRenderer.startLabel(buffer, in_styleClass, onclick, style);
308             
309             // Render the image.
310
lc_treeviewRenderer.renderImage(buffer, in_request, lc_info, item);
311             
312             // Render the label.
313
lc_treeviewRenderer.renderLabel(buffer, in_request, in_servletcontext, lc_info, item);
314             
315             // End the label TD.
316
lc_treeviewRenderer.endLabel(buffer);
317             
318             lc_treeviewRenderer.renderActions(buffer, in_request, in_servletcontext, lc_info, item);
319             
320             if (lc_info.hasSubMenus) {
321                 lc_numberOfMenusPrinted = lc_treeviewRenderer.endSubMenu(buffer, in_request, in_servletcontext, lc_numberOfMenusPrinted, item, lc_info);
322             }
323
324             lc_treeviewRenderer.endRow(buffer);
325         }
326         return lc_numberOfMenusPrinted;
327     }
328     
329     /**
330      * Returns true if the node is close.
331      * A node is close by default. It is open if the page has already been displayed and the user has opened it.
332      * This would have lead javascript code to modify a cookie.
333      * So all we have to do is to read the cookie.
334      * <br/><br/>
335      * The cookie holds the list of the open node and uses the following format: _<node1 id>_<node2 id>_<node3 id>_
336      */

337     public static boolean isNodeClosed(HttpServletRequest JavaDoc in_request, String JavaDoc in_path) {
338         Cookie JavaDoc[] lc_cookies = in_request.getCookies();
339         
340         if (lc_cookies==null) return true;
341         for (int i=0;i<lc_cookies.length;i++) {
342             Cookie JavaDoc lc_cookie = lc_cookies[i];
343             if (lc_cookie.getName().equals("treeView")) {
344                 if (lc_cookie.getValue().indexOf("_treeView" + in_path + "_")==-1) {
345                     return true;
346                 } else {
347                     return false;
348                 }
349             }
350         }
351         return true;
352     }
353     
354
355 public int doStartLayoutTag() throws JspException JavaDoc {
356     return EVAL_BODY_INCLUDE;
357 }
358 public void setAutoIncrement(String JavaDoc in_value) {
359     if ("true".equalsIgnoreCase(in_value)) {
360         autoIncrement = true;
361     } else {
362         autoIncrement = false;
363     }
364 }
365 public void release() {
366     super.release();
367     autoIncrement = true;
368     expandedLevelsAtFirst = -1;
369 }
370
371     /**
372      * @param expandedLevelsAtFirst The expandedLevelsAtFirst to set.
373      */

374     public final void setExpandedLevelsAtFirst(int expandedLevelsAtFirst)
375     {
376         this.expandedLevelsAtFirst = expandedLevelsAtFirst;
377     }
378     
379     /**
380      * Build an URL for the iframe.
381      * The url must be relative to the current URL, otherwise
382      * some version of IE will complain in SSL mode.
383      */

384     private String JavaDoc buildIFrameSource(HttpServletRequest JavaDoc in_request) {
385         String JavaDoc action = LayoutUtils.getSkin(in_request.getSession()).getProperty(Skin.TREEVIEW_ACTION, DEFAULT_TREEVIEW_ACTION);
386         return in_request.getContextPath() + "/" + action + "?iframe=iframe";
387     }
388 }
389
Popular Tags