123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- /*
- @ITMillApache2LicenseForJavaFiles@
- */
-
- package com.itmill.toolkit.terminal.gwt.client.ui;
-
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
-
- import com.google.gwt.user.client.DOM;
- import com.google.gwt.user.client.Element;
- import com.google.gwt.user.client.Event;
- import com.google.gwt.user.client.Window;
- import com.google.gwt.user.client.ui.FlowPanel;
- import com.google.gwt.user.client.ui.SimplePanel;
- import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
- import com.itmill.toolkit.terminal.gwt.client.Paintable;
- import com.itmill.toolkit.terminal.gwt.client.UIDL;
- import com.itmill.toolkit.terminal.gwt.client.Util;
-
- /**
- *
- */
- public class ITree extends FlowPanel implements Paintable {
-
- public static final String CLASSNAME = "i-tree";
-
- private Set selectedIds = new HashSet();
- private ApplicationConnection client;
- private String paintableId;
- private boolean selectable;
- private boolean isMultiselect;
-
- private final HashMap keyToNode = new HashMap();
-
- /**
- * This map contains captions and icon urls for actions like: * "33_c" ->
- * "Edit" * "33_i" -> "http://dom.com/edit.png"
- */
- private final HashMap actionMap = new HashMap();
-
- private boolean immediate;
-
- private boolean isNullSelectionAllowed = true;
-
- private boolean disabled = false;
-
- private boolean readonly;
-
- public ITree() {
- super();
- setStyleName(CLASSNAME);
- }
-
- private void updateActionMap(UIDL c) {
- final Iterator it = c.getChildIterator();
- while (it.hasNext()) {
- final UIDL action = (UIDL) it.next();
- final String key = action.getStringAttribute("key");
- final String caption = action.getStringAttribute("caption");
- actionMap.put(key + "_c", caption);
- if (action.hasAttribute("icon")) {
- // TODO need some uri handling ??
- actionMap.put(key + "_i", client.translateToolkitUri(action
- .getStringAttribute("icon")));
- }
- }
-
- }
-
- public String getActionCaption(String actionKey) {
- return (String) actionMap.get(actionKey + "_c");
- }
-
- public String getActionIcon(String actionKey) {
- return (String) actionMap.get(actionKey + "_i");
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- // Ensure correct implementation and let container manage caption
- if (client.updateComponent(this, uidl, true)) {
- return;
- }
-
- this.client = client;
-
- if (uidl.hasAttribute("partialUpdate")) {
- handleUpdate(uidl);
- return;
- }
-
- paintableId = uidl.getId();
-
- immediate = uidl.hasAttribute("immediate");
-
- disabled = uidl.getBooleanAttribute("disabled");
- readonly = uidl.getBooleanAttribute("readonly");
-
- isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
-
- clear();
- for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
- final UIDL childUidl = (UIDL) i.next();
- if ("actions".equals(childUidl.getTag())) {
- updateActionMap(childUidl);
- continue;
- }
- final TreeNode childTree = new TreeNode();
- this.add(childTree);
- childTree.updateFromUIDL(childUidl, client);
- }
- final String selectMode = uidl.getStringAttribute("selectmode");
- selectable = selectMode != null;
- isMultiselect = "multi".equals(selectMode);
-
- selectedIds = uidl.getStringArrayVariableAsSet("selected");
-
- }
-
- private void handleUpdate(UIDL uidl) {
- final TreeNode rootNode = (TreeNode) keyToNode.get(uidl
- .getStringAttribute("rootKey"));
- if (rootNode != null) {
- if (!rootNode.getState()) {
- // expanding node happened server side
- rootNode.setState(true, false);
- }
- rootNode.renderChildNodes(uidl.getChildIterator());
- }
-
- }
-
- public void setSelected(TreeNode treeNode, boolean selected) {
- if (selected) {
- if (!isMultiselect) {
- while (selectedIds.size() > 0) {
- final String id = (String) selectedIds.iterator().next();
- final TreeNode oldSelection = (TreeNode) keyToNode.get(id);
- oldSelection.setSelected(false);
- selectedIds.remove(id);
- }
- }
- treeNode.setSelected(true);
- selectedIds.add(treeNode.key);
- } else {
- if (!isNullSelectionAllowed) {
- if (!isMultiselect || selectedIds.size() == 1) {
- return;
- }
- }
- selectedIds.remove(treeNode.key);
- treeNode.setSelected(false);
- }
- client.updateVariable(paintableId, "selected", selectedIds.toArray(),
- immediate);
- }
-
- public boolean isSelected(TreeNode treeNode) {
- return selectedIds.contains(treeNode.key);
- }
-
- protected class TreeNode extends SimplePanel implements ActionOwner {
-
- public static final String CLASSNAME = "i-tree-node";
-
- String key;
-
- private String[] actionKeys = null;
-
- private boolean childrenLoaded;
-
- private Element nodeCaptionDiv;
-
- protected Element nodeCaptionSpan;
-
- private FlowPanel childNodeContainer;
-
- private boolean open;
-
- private Icon icon;
-
- public TreeNode() {
- constructDom();
- sinkEvents(Event.ONCLICK);
- }
-
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- if (disabled) {
- return;
- }
- final Element target = DOM.eventGetTarget(event);
- if (DOM.compare(getElement(), target)) {
- // state change
- toggleState();
- } else if (!readonly && DOM.compare(target, nodeCaptionSpan)) {
- // caption click = selection change
- toggleSelection();
- }
-
- }
-
- private void toggleSelection() {
- if (selectable) {
- ITree.this.setSelected(this, !isSelected());
- }
- }
-
- private void toggleState() {
- setState(!getState(), true);
- }
-
- protected void constructDom() {
- final Element root = DOM.createDiv();
- nodeCaptionDiv = DOM.createDiv();
- DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
- + "-caption");
- nodeCaptionSpan = DOM.createSpan();
- DOM.appendChild(root, nodeCaptionDiv);
- DOM.appendChild(nodeCaptionDiv, nodeCaptionSpan);
- setElement(root);
-
- childNodeContainer = new FlowPanel();
- childNodeContainer.setStylePrimaryName(CLASSNAME + "-children");
- setWidget(childNodeContainer);
- }
-
- public void onDetach() {
- Util.removeContextMenuEvent(nodeCaptionSpan);
- super.onDetach();
- }
-
- public void onAttach() {
- attachContextMenuEvent(nodeCaptionSpan);
- super.onAttach();
- }
-
- public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- setText(uidl.getStringAttribute("caption"));
- key = uidl.getStringAttribute("key");
-
- keyToNode.put(key, this);
-
- if (uidl.hasAttribute("al")) {
- actionKeys = uidl.getStringArrayAttribute("al");
- }
-
- if (uidl.getTag().equals("node")) {
- if (uidl.getChildCount() == 0) {
- childNodeContainer.setVisible(false);
- } else {
- renderChildNodes(uidl.getChildIterator());
- childrenLoaded = true;
- }
- } else {
- addStyleName(CLASSNAME + "-leaf");
- }
- addStyleName(CLASSNAME);
-
- if (uidl.getBooleanAttribute("expanded") && !getState()) {
- setState(true, false);
- }
-
- if (uidl.getBooleanAttribute("selected")) {
- setSelected(true);
- }
-
- if (uidl.hasAttribute("icon")) {
- if (icon == null) {
- icon = new Icon(client);
- DOM.insertBefore(nodeCaptionDiv, icon.getElement(),
- nodeCaptionSpan);
- }
- icon.setUri(uidl.getStringAttribute("icon"));
- } else {
- if (icon != null) {
- DOM.removeChild(nodeCaptionDiv, icon.getElement());
- icon = null;
- }
- }
- }
-
- private void setState(boolean state, boolean notifyServer) {
- if (open == state) {
- return;
- }
- if (state) {
- if (!childrenLoaded && notifyServer) {
- client.updateVariable(paintableId, "requestChildTree",
- true, false);
- }
- if (notifyServer) {
- client.updateVariable(paintableId, "expand",
- new String[] { key }, true);
- }
- addStyleName(CLASSNAME + "-expanded");
- childNodeContainer.setVisible(true);
- } else {
- removeStyleName(CLASSNAME + "-expanded");
- childNodeContainer.setVisible(false);
- if (notifyServer) {
- client.updateVariable(paintableId, "collapse",
- new String[] { key }, true);
- }
- }
-
- open = state;
- }
-
- private boolean getState() {
- return open;
- }
-
- private void setText(String text) {
- DOM.setInnerText(nodeCaptionSpan, text);
- }
-
- private void renderChildNodes(Iterator i) {
- childNodeContainer.clear();
- childNodeContainer.setVisible(true);
- while (i.hasNext()) {
- final UIDL childUidl = (UIDL) i.next();
- // actions are in bit weird place, don't mix them with children,
- // but current node's actions
- if ("actions".equals(childUidl.getTag())) {
- updateActionMap(childUidl);
- continue;
- }
- final TreeNode childTree = new TreeNode();
- childNodeContainer.add(childTree);
- childTree.updateFromUIDL(childUidl, client);
- }
- childrenLoaded = true;
- }
-
- public boolean isChildrenLoaded() {
- return childrenLoaded;
- }
-
- public Action[] getActions() {
- if (actionKeys == null) {
- return new Action[] {};
- }
- final Action[] actions = new Action[actionKeys.length];
- for (int i = 0; i < actions.length; i++) {
- final String actionKey = actionKeys[i];
- final TreeAction a = new TreeAction(this, String.valueOf(key),
- actionKey);
- a.setCaption(getActionCaption(actionKey));
- a.setIconUrl(getActionIcon(actionKey));
- actions[i] = a;
- }
- return actions;
- }
-
- public ApplicationConnection getClient() {
- return client;
- }
-
- public String getPaintableId() {
- return paintableId;
- }
-
- /**
- * Adds/removes IT Mill Toolkit spesific style name. This method ought
- * to be called only from Tree.
- *
- * @param selected
- */
- public void setSelected(boolean selected) {
- // add style name to caption dom structure only, not to subtree
- setStyleName(nodeCaptionDiv, "i-tree-node-selected", selected);
- }
-
- public boolean isSelected() {
- return ITree.this.isSelected(this);
- }
-
- public void showContextMenu(Event event) {
- if (!readonly && !disabled) {
- if (actionKeys != null) {
- int left = DOM.eventGetClientX(event);
- int top = DOM.eventGetClientY(event);
- top += Window.getScrollTop();
- left += Window.getScrollLeft();
- client.getContextMenu().showAt(this, left, top);
- }
- DOM.eventCancelBubble(event, true);
- }
-
- }
-
- private native void attachContextMenuEvent(Element el)
- /*-{
- var node = this;
- el.oncontextmenu = function(e) {
- if(!e)
- e = $wnd.event;
- node.@com.itmill.toolkit.terminal.gwt.client.ui.ITree.TreeNode::showContextMenu(Lcom/google/gwt/user/client/Event;)(e);
- return false;
- };
- }-*/;
-
- }
- }
|