1
2
3
4
5
6
7
8 package com.extjs.gxt.ui.client.widget.treepanel;
9
10 import com.extjs.gxt.ui.client.GXT;
11 import com.extjs.gxt.ui.client.aria.FocusFrame;
12 import com.extjs.gxt.ui.client.core.El;
13 import com.extjs.gxt.ui.client.core.XDOM;
14 import com.extjs.gxt.ui.client.data.ModelData;
15 import com.extjs.gxt.ui.client.event.Events;
16 import com.extjs.gxt.ui.client.event.TreePanelEvent;
17 import com.extjs.gxt.ui.client.store.Store;
18 import com.extjs.gxt.ui.client.store.TreeStore;
19 import com.extjs.gxt.ui.client.util.IconHelper;
20 import com.extjs.gxt.ui.client.util.Util;
21 import com.extjs.gxt.ui.client.widget.Component;
22 import com.extjs.gxt.ui.client.widget.treepanel.TreePanel.Joint;
23 import com.extjs.gxt.ui.client.widget.treepanel.TreePanel.TreeNode;
24 import com.google.gwt.dom.client.NodeList;
25 import com.google.gwt.user.client.DOM;
26 import com.google.gwt.user.client.Element;
27 import com.google.gwt.user.client.Event;
28 import com.google.gwt.user.client.ui.AbstractImagePrototype;
29 import com.google.gwt.user.client.ui.Accessibility;
30
31 @SuppressWarnings({"unchecked", "rawtypes"})
32 public class TreePanelView<M extends ModelData> {
33
34 public enum TreeViewRenderMode {
35 ALL, BODY, CONTAINER, MAIN
36 };
37
38 protected TreeNode over;
39 protected TreePanel<M> tree;
40 protected TreeStore<M> treeStore;
41
42 private int cacheSize = 20;
43 private int cleanDelay = 500;
44 private int scrollDelay = 0;
45
46 public void bind(Component component, Store store) {
47 this.tree = (TreePanel) component;
48 this.treeStore = (TreeStore) store;
49 }
50
51 public void collapse(TreeNode node) {
52 getContainer(node).getStyle().setProperty("display", "none");
53 tree.refresh((M) node.m);
54 if (GXT.isFocusManagerEnabled()) {
55 Accessibility.setState((Element) node.getElement().getFirstChildElement(), "aria-expanded", "false");
56 FocusFrame.get().sync(tree);
57 }
58 }
59
60 public void expand(TreeNode node) {
61 getContainer(node).getStyle().setProperty("display", "block");
62 tree.refresh((M) node.m);
63 if (GXT.isFocusManagerEnabled()) {
64 FocusFrame.get().sync(tree);
65 Accessibility.setState((Element) node.getElement().getFirstChildElement(), "aria-expanded", "true");
66 }
67 }
68
69 public int getCacheSize() {
70 return cacheSize;
71 }
72
73 public Element getCheckElement(TreeNode node) {
74 if (node.check == null) {
75 node.check = getElementContainer(node) != null
76 ? ((NodeList<Element>) getElementContainer(node).getChildNodes().cast()).getItem(2) : null;
77 }
78 return node.check;
79 }
80
81 public int getCleanDelay() {
82 return cleanDelay;
83 }
84
85 public Element getContainer(TreeNode node) {
86 if (node.container == null) {
87 String s = getTemplate(node.m, null, null, null, false, false, null, 0, TreeViewRenderMode.CONTAINER);
88 node.container = node.getElement().appendChild(XDOM.create(s));
89 }
90 return node.container;
91 }
92
93 public Element getElementContainer(TreeNode node) {
94 if (node.elContainer == null) {
95 node.elContainer = node.getElement() != null ? (Element) node.getElement().getFirstChild() : null;
96 }
97 return node.elContainer;
98 }
99
100 public Element getIconElement(TreeNode node) {
101 if (node.icon == null) {
102 node.icon = getElementContainer(node) != null
103 ? ((NodeList<Element>) getElementContainer(node).getChildNodes().cast()).getItem(3) : null;
104 }
105 return node.icon;
106 }
107
108 public Element getJointElement(TreeNode node) {
109 if (node.joint == null) {
110 node.joint = ((NodeList<Element>) getElementContainer(node).getChildNodes().cast()).getItem(1);
111 }
112 return node.joint;
113 }
114
115 public int getScrollDelay() {
116 return scrollDelay;
117 }
118
119 public String getTemplate(ModelData m, String id, String text, AbstractImagePrototype icon, boolean checkable,
120 boolean checked, Joint joint, int level, TreeViewRenderMode renderMode) {
121 if (renderMode == TreeViewRenderMode.CONTAINER) {
122 return "<div unselectable=on class=\"x-tree3-node-ct\" role=\"group\"></div>";
123 }
124 StringBuilder sb = new StringBuilder();
125 if (renderMode == TreeViewRenderMode.ALL || renderMode == TreeViewRenderMode.MAIN) {
126 sb.append("<div unselectable=on id=\"");
127 sb.append(id);
128 sb.append("\"");
129
130 sb.append(" class=\"x-tree3-node\" role=\"presentation\">");
131
132 String cls = "x-tree3-el";
133 if (GXT.isHighContrastMode) {
134 switch (joint) {
135 case COLLAPSED:
136 cls += " x-tree3-node-joint-collapse";
137 break;
138 case EXPANDED:
139 cls += " x-tree3-node-joint-expand";
140 break;
141 }
142 }
143
144 sb.append("<div unselectable=on class=\"" + cls + "\" id=\"" + tree.getId() + "__" + id + "\" role=\"treeitem\" ");
145 sb.append(" aria-level=\"" + (level + 1) + "\">");
146 }
147 if (renderMode == TreeViewRenderMode.ALL || renderMode == TreeViewRenderMode.BODY) {
148 Element jointElement = null;
149 switch (joint) {
150 case COLLAPSED:
151 jointElement = (Element) tree.getStyle().getJointCollapsedIcon().createElement().cast();
152 break;
153 case EXPANDED:
154 jointElement = (Element) tree.getStyle().getJointExpandedIcon().createElement().cast();
155 break;
156 }
157
158 if (jointElement != null) {
159 El.fly(jointElement).addStyleName("x-tree3-node-joint");
160 }
161
162 sb.append("<img src=\"");
163 sb.append(GXT.BLANK_IMAGE_URL);
164 sb.append("\" style=\"height: 18px; width: ");
165 sb.append(level * getIndenting(findNode((M) m)));
166 sb.append("px;\" />");
167 sb.append(jointElement == null ? "<img src=\"" + GXT.BLANK_IMAGE_URL
168 + "\" style=\"width: 16px\" class=\"x-tree3-node-joint\" />" : DOM.toString(jointElement));
169 if (checkable) {
170 Element e = (Element) (checked ? GXT.IMAGES.checked().createElement().cast()
171 : GXT.IMAGES.unchecked().createElement().cast());
172 El.fly(e).addStyleName("x-tree3-node-check");
173 sb.append(DOM.toString(e));
174 } else {
175 sb.append("<span class=\"x-tree3-node-check\"></span>");
176 }
177 if (icon != null) {
178 Element e = icon.createElement().cast();
179 El.fly(e).addStyleName("x-tree3-node-icon");
180 sb.append(DOM.toString(e));
181 } else {
182 sb.append("<span class=\"x-tree3-node-icon\"></span>");
183 }
184 sb.append("<span unselectable=on class=\"x-tree3-node-text\">");
185 sb.append(text);
186 sb.append("</span>");
187 }
188
189 if (renderMode == TreeViewRenderMode.ALL || renderMode == TreeViewRenderMode.MAIN) {
190 sb.append("</div>");
191 sb.append("</div>");
192 }
193 return sb.toString();
194 }
195
196 public Element getTextElement(TreeNode node) {
197 if (node.text == null) {
198 node.text = getElementContainer(node) != null
199 ? ((NodeList<Element>) getElementContainer(node).getChildNodes().cast()).getItem(4) : null;
200 }
201 return node.text;
202
203 }
204
205 public boolean isSelectableTarget(M m, Element target) {
206 TreeNode n = findNode(m);
207 if (n == null) {
208 return false;
209 }
210 boolean isNotJointTarget = false;
211 if (GXT.isIE6) {
212 isNotJointTarget = !El.fly(target).getParent().hasStyleName("x-tree3-node-joint");
213 } else {
214 isNotJointTarget = !El.fly(target).hasStyleName("x-tree3-node-joint");
215 }
216 if (isNotJointTarget && tree.isCheckable()) {
217 boolean isNotCheckTarget = !El.fly(target).hasStyleName("x-tree3-node-check");
218 return isNotCheckTarget;
219 }
220 return isNotJointTarget;
221 }
222
223 public void onCheckChange(TreeNode node, boolean checkable, boolean check) {
224 Element checkEl = (Element) getCheckElement(node);
225 if (checkEl != null) {
226 Element e;
227 if (checkable) {
228 if (check) {
229 e = (Element) GXT.IMAGES.checked().createElement().cast();
230 } else {
231 e = (Element) GXT.IMAGES.unchecked().createElement().cast();
232 }
233 } else {
234 e = DOM.createSpan();
235 }
236 El.fly(e).addStyleName("x-tree3-node-check");
237 node.check = (Element) node.getElement().getFirstChild().insertBefore(e, checkEl);
238 El.fly(checkEl).remove();
239 }
240 }
241
242 public void onDropChange(TreeNode node, boolean drop) {
243 El.fly(getElementContainer(node)).setStyleName("x-ftree2-node-drop", drop);
244 }
245
246 public void onEvent(TreePanelEvent ce) {
247 int type = ce.getEventTypeInt();
248 switch (type) {
249 case Event.ONMOUSEOVER:
250 if (tree.isTrackMouseOver()) {
251 onMouseOver(ce);
252 }
253 break;
254 case Event.ONMOUSEOUT:
255 if (tree.isTrackMouseOver()) {
256 onMouseOut(ce);
257 }
258 break;
259 }
260 }
261
262 public void onIconStyleChange(TreeNode node, AbstractImagePrototype icon) {
263 Element iconEl = getIconElement(node);
264 if (iconEl != null) {
265 Element e;
266 if (icon != null) {
267 e = (Element) icon.createElement().cast();
268 } else {
269 e = DOM.createSpan();
270 }
271 El.fly(e).addStyleName("x-tree3-node-icon");
272 node.icon = (Element) node.getElement().getFirstChild().insertBefore(e, iconEl);
273 El.fly(iconEl).remove();
274 }
275 }
276
277 public void onJointChange(TreeNode node, Joint joint) {
278 Element jointEl = getJointElement(node);
279 if (jointEl != null) {
280 Element e;
281 switch (joint) {
282 case COLLAPSED:
283 e = (Element) tree.getStyle().getJointCollapsedIcon().createElement().cast();
284 if (GXT.isHighContrastMode) {
285 El.fly(node.elContainer).addStyleName("x-tree3-node-joint-collapse").removeStyleName(
286 "x-tree3-node-joint-expand");
287 }
288 break;
289 case EXPANDED:
290 e = (Element) tree.getStyle().getJointExpandedIcon().createElement().cast();
291 if (GXT.isHighContrastMode) {
292 El.fly(node.elContainer).addStyleName("x-tree3-node-joint-expand").removeStyleName(
293 "x-tree3-node-joint-collapse");
294 }
295 break;
296 default:
297 e = XDOM.create("<img src=\"" + GXT.BLANK_IMAGE_URL + "\" width=\"16px\"/>");
298 if (GXT.isHighContrastMode) {
299 El.fly(node.elContainer).removeStyleName("x-tree3-node-joint-collapse").removeStyleName(
300 "x-tree3-node-joint-expand");
301 }
302 }
303
304 El.fly(e).addStyleName("x-tree3-node-joint");
305 node.joint = (Element) node.getElement().getFirstChild().insertBefore(e, jointEl);
306 El.fly(jointEl).remove();
307 }
308 }
309
310 public void onLoading(TreeNode node) {
311 onIconStyleChange(node, IconHelper.createStyle("x-tree3-loading"));
312 }
313
314 public void onOverChange(TreeNode node, boolean select) {
315 El.fly(getElementContainer(node)).setStyleName("x-ftree2-node-over", select);
316 }
317
318 public void onSelectChange(M model, boolean select) {
319 if (select) {
320 tree.setExpanded(treeStore.getParent(model), true);
321 }
322 TreeNode node = findNode(model);
323 if (node != null) {
324 Element e = getElementContainer(node);
325 if (e != null) {
326 El.fly(e).setStyleName("x-ftree2-selected", select);
327 if (select) {
328 String tid = tree.getId();
329 Accessibility.setState(tree.getElement(), "aria-activedescendant", tid + "__" + node.getElement().getId());
330 }
331 }
332 }
333 }
334
335 public void onTextChange(TreeNode node, String text) {
336 Element textEl = getTextElement(node);
337 if (textEl != null) {
338 textEl.setInnerHTML(Util.isEmptyString(text) ? " " : text);
339 }
340 }
341
342 public void setCacheSize(int cacheSize) {
343 this.cacheSize = cacheSize;
344 }
345
346 public void setCleanDelay(int cleanDelay) {
347 this.cleanDelay = cleanDelay;
348 }
349
350 public void setScrollDelay(int scrollDelay) {
351 this.scrollDelay = scrollDelay;
352 }
353
354 protected TreeNode findNode(M m){
355 return tree.findNode(m);
356 }
357
358 protected int getCalculatedRowHeight() {
359 return 21;
360 }
361
362 protected int getIndenting(TreeNode node) {
363 return 18;
364 }
365
366 protected void onMouseOut(TreePanelEvent ce) {
367 if (over != null) {
368 onOverChange(over, false);
369 over = null;
370 }
371 }
372
373 protected void onMouseOver(TreePanelEvent ce) {
374 if (ce.getNode() != null) {
375 if (over != ce.getNode()) {
376
377 tree.fireEvent(Events.OnMouseOver, ce);
378
379 onMouseOut(ce);
380 over = ce.getNode();
381 onOverChange(over, true);
382 }
383 }
384 }
385
386 }