You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. package com.itmill.toolkit.terminal.gwt.client.ui;
  2. import java.util.HashMap;
  3. import java.util.HashSet;
  4. import java.util.Iterator;
  5. import java.util.Set;
  6. import com.google.gwt.user.client.DOM;
  7. import com.google.gwt.user.client.Element;
  8. import com.google.gwt.user.client.Event;
  9. import com.google.gwt.user.client.Window;
  10. import com.google.gwt.user.client.ui.Tree;
  11. import com.google.gwt.user.client.ui.TreeItem;
  12. import com.google.gwt.user.client.ui.TreeListener;
  13. import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
  14. import com.itmill.toolkit.terminal.gwt.client.Paintable;
  15. import com.itmill.toolkit.terminal.gwt.client.UIDL;
  16. import com.itmill.toolkit.terminal.gwt.client.Util;
  17. /**
  18. * TODO dump GWT's Tree implementation and use Toolkit 4 style
  19. * TODO update node close/opens to server (even if no content fetch is needed)
  20. *
  21. * DOM structure
  22. *
  23. */
  24. public class ITree extends Tree implements Paintable {
  25. public static final String CLASSNAME = "i-tree";
  26. Set selectedIds = new HashSet();
  27. ApplicationConnection client;
  28. String paintableId;
  29. private boolean selectable;
  30. private boolean multiselect;
  31. private HashMap keyToNode = new HashMap();
  32. /**
  33. * This map contains captions and icon urls for
  34. * actions like:
  35. * * "33_c" -> "Edit"
  36. * * "33_i" -> "http://dom.com/edit.png"
  37. */
  38. private HashMap actionMap = new HashMap();
  39. private boolean immediate;
  40. public ITree() {
  41. super();
  42. setStyleName(CLASSNAME);
  43. }
  44. private void updateActionMap(UIDL c) {
  45. Iterator it = c.getChildIterator();
  46. while(it.hasNext()) {
  47. UIDL action = (UIDL) it.next();
  48. String key = action.getStringAttribute("key");
  49. String caption = action.getStringAttribute("caption");
  50. actionMap.put(key + "_c", caption);
  51. if(action.hasAttribute("icon")) {
  52. // TODO need some uri handling ??
  53. actionMap.put(key + "_i", action.getStringAttribute("icon"));
  54. }
  55. }
  56. }
  57. public String getActionCaption(String actionKey) {
  58. return (String) actionMap.get(actionKey + "_c");
  59. }
  60. public String getActionIcon(String actionKey) {
  61. return (String) actionMap.get(actionKey + "_i");
  62. }
  63. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  64. // Ensure correct implementation and let container manage caption
  65. if (client.updateComponent(this, uidl, true))
  66. return;
  67. this.client = client;
  68. if(uidl.hasAttribute("partialUpdate")) {
  69. handleUpdate(uidl);
  70. return;
  71. }
  72. this.paintableId = uidl.getId();
  73. this.immediate = uidl.hasAttribute("immediate");
  74. clear();
  75. for (Iterator i = uidl.getChildIterator(); i.hasNext();) {
  76. UIDL childUidl = (UIDL)i.next();
  77. if("actions".equals(childUidl.getTag())){
  78. updateActionMap(childUidl);
  79. continue;
  80. }
  81. TreeNode childTree = new TreeNode();
  82. addItem(childTree);
  83. childTree.updateFromUIDL(childUidl, client);
  84. }
  85. String selectMode = uidl.getStringAttribute("selectmode");
  86. selectable = selectMode != null;
  87. multiselect = "multi".equals(selectMode);
  88. addTreeListener(new TreeListener() {
  89. public void onTreeItemStateChanged(TreeItem item) {
  90. if (item instanceof TreeNode) {
  91. TreeNode tn = (TreeNode) item;
  92. if(item.getState()) {
  93. if(!tn.isChildrenLoaded()) {
  94. String key = tn.key;
  95. ITree.this.client.updateVariable(paintableId, "expand", new String[] {key}, true);
  96. }
  97. } else {
  98. // TODO collapse
  99. }
  100. }
  101. }
  102. public void onTreeItemSelected(TreeItem item) {
  103. TreeNode n = ((TreeNode) item);
  104. if (!selectable) return;
  105. String key = n.key;
  106. if (key != null) {
  107. if(selectedIds.contains(key) && multiselect) {
  108. selectedIds.remove(key);
  109. n.setISelected(false);
  110. } else {
  111. if (!multiselect) {
  112. selectedIds.clear();
  113. }
  114. selectedIds.add(key);
  115. n.setISelected(true);
  116. }
  117. ITree.this.client.updateVariable(ITree.this.paintableId, "selected", selectedIds.toArray(), immediate);
  118. }
  119. }
  120. });
  121. selectedIds = uidl.getStringArrayVariableAsSet("selected");
  122. }
  123. private void handleUpdate(UIDL uidl) {
  124. TreeNode rootNode = (TreeNode) keyToNode.get(uidl.getStringAttribute("rootKey"));
  125. if(rootNode != null) {
  126. rootNode.renderChildNodes(uidl.getChildIterator());
  127. }
  128. }
  129. private class TreeNode extends TreeItem implements IActionOwner {
  130. String key;
  131. boolean isLeaf = false;
  132. private String[] actionKeys = null;
  133. private boolean childrenLoaded;
  134. public TreeNode() {
  135. super();
  136. attachContextMenuEvent(getElement());
  137. }
  138. public void remove() {
  139. Util.removeContextMenuEvent(getElement());
  140. super.remove();
  141. }
  142. public void setSelected(boolean selected) {
  143. if(!selected && !ITree.this.multiselect) {
  144. this.setISelected(false);
  145. }
  146. super.setSelected(selected);
  147. }
  148. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  149. this.setText(uidl.getStringAttribute("caption"));
  150. key = uidl.getStringAttribute("key");
  151. keyToNode.put(key, this);
  152. if(uidl.hasAttribute("al"))
  153. actionKeys = uidl.getStringArrayAttribute("al");
  154. if(uidl.getTag().equals("node")) {
  155. isLeaf = false;
  156. if(uidl.getChidlCount() == 0) {
  157. TreeNode childTree = new TreeNode();
  158. childTree.setText("Loading...");
  159. childrenLoaded = false;
  160. this.addItem(childTree);
  161. } else {
  162. renderChildNodes(uidl.getChildIterator());
  163. }
  164. } else {
  165. isLeaf = true;
  166. }
  167. if(uidl.getBooleanAttribute("expanded") && !getState()) {
  168. setState(true);
  169. }
  170. setSelected(uidl.getBooleanAttribute("selected"));
  171. }
  172. private void renderChildNodes(Iterator i) {
  173. removeItems();
  174. while (i.hasNext()) {
  175. UIDL childUidl = (UIDL)i.next();
  176. if("actions".equals(childUidl.getTag())) {
  177. updateActionMap(childUidl);
  178. continue;
  179. }
  180. TreeNode childTree = new TreeNode();
  181. this.addItem(childTree);
  182. childTree.updateFromUIDL(childUidl, client);
  183. }
  184. childrenLoaded = true;
  185. }
  186. public boolean isChildrenLoaded() {
  187. return childrenLoaded;
  188. }
  189. public IAction[] getActions() {
  190. if(actionKeys == null)
  191. return new IAction[] {};
  192. IAction[] actions = new IAction[actionKeys.length];
  193. for (int i = 0; i < actions.length; i++) {
  194. String actionKey = actionKeys[i];
  195. ITreeAction a = new ITreeAction(this, String.valueOf(key), actionKey);
  196. a.setCaption(getActionCaption(actionKey));
  197. actions[i] = a;
  198. }
  199. return actions;
  200. }
  201. public ApplicationConnection getClient() {
  202. return client;
  203. }
  204. public String getPaintableId() {
  205. return paintableId;
  206. }
  207. /**
  208. * Adds/removes IT Mill Toolkit spesific style name.
  209. * (GWT treenode does not support multiselects)
  210. *
  211. * @param selected
  212. */
  213. public void setISelected(boolean selected) {
  214. setStyleName(getElement(), "i-tree-node-selected", selected);
  215. }
  216. public void showContextMenu(Event event) {
  217. if(actionKeys != null) {
  218. int left = DOM.eventGetClientX(event);
  219. int top = DOM.eventGetClientY(event);
  220. top += Window.getScrollTop();
  221. left += Window.getScrollLeft();
  222. client.getContextMenu().showAt(this, left, top);
  223. }
  224. DOM.eventCancelBubble(event, true);
  225. }
  226. private native void attachContextMenuEvent(Element el) /*-{
  227. var node = this;
  228. el.oncontextmenu = function(e) {
  229. if(!e)
  230. e = $wnd.event;
  231. node.@com.itmill.toolkit.terminal.gwt.client.ui.ITree.TreeNode::showContextMenu(Lcom/google/gwt/user/client/Event;)(e);
  232. return false;
  233. };
  234. }-*/;
  235. }
  236. }