package com.gwt.ui.client.tree; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.logical.shared.OpenEvent; import com.google.gwt.event.logical.shared.OpenHandler; import com.google.gwt.event.logical.shared.SelectionEvent; import com.google.gwt.event.logical.shared.SelectionHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Tree; import com.google.gwt.user.client.ui.TreeItem; import com.google.gwt.user.client.ui.Widget; /** * * @author ibouakl * */ public class AdvanceTree extends Tree { private HashMap<String, TreePopupMenu> contextMenus = new HashMap<String, TreePopupMenu>(); private ArrayList<AdvanceTreeListener> listeners = new ArrayList<AdvanceTreeListener>(); private boolean multiSelectionEnabled = false; private ArrayList<TreeItem> selectedItems = new ArrayList<TreeItem>(); private String selectedLevel = ""; /** * A constructor for this class. */ public AdvanceTree() { super(); init(); } /** * A constructor for this class. */ public AdvanceTree(Tree.Resources resources) { super(resources); init(); } protected static native void preventBrowserContextMenu(JavaScriptObject element) /*-{ element.oncontextmenu = function() { return false; } }-*/; /** * Note that all the items in the tree are converted to GWT HTML object before adding to the tree. Therefore, the GWT Tree.getText() * method will return a null. */ public TreeItem addItem(String itemText) { HTML html = new HTML(itemText); preventBrowserContextMenu(html.getElement()); return super.addItem(html); } /** * Add a AdvanceTree object to the root of the tree. * * @param item item to add. */ public void addItem(AdvanceTreeItem item) { super.addItem(item); preventBrowserContextMenu(item.getElement()); } public void addItem(TreeItem item) { super.addItem(item); preventBrowserContextMenu(item.getElement()); } public TreeItem addItem(Widget widget) { preventBrowserContextMenu(widget.getElement()); return super.addItem(widget); } /** * Add a tree listener. * * @param listener the listener object. */ public void addTreeListener(AdvanceTreeListener listener) { listeners.add(listener); } /** * @param item a tree item. * @return the level */ public static String getLevel(TreeItem item) { ArrayList<Integer> items = new ArrayList<Integer>(); do { if (item instanceof AdvanceTreeItem) { items.add(new Integer(((AdvanceTreeItem)item).getType())); } else { items.add(new Integer(0)); } item = item.getParentItem(); } while (item != null); StringBuffer buffer = new StringBuffer(); Collections.reverse(items); for (int i = 0; i < items.size(); i++) { if (i > 0) { buffer.append('.'); } buffer.append(((Integer)items.get(i)).toString()); } return buffer.toString(); } /** * Note that if multi-selection is enabled, this method returns the item selected first. For trees with multi-selection, the * getSelectedItems() method must be used. */ public TreeItem getSelectedItem() { if (selectedItems.size() == 0) { return null; } return selectedItems.get(0); } /** * Returns the selected items. * * @return selected items. */ public TreeItem[] getSelectedItems() { TreeItem[] items = convertSelectedToArray(); return items; } /** * Returns if multi-selection is enabled. * * @return Returns the multiSelectionEnabled. */ public boolean isMultiSelectionEnabled() { return multiSelectionEnabled; } /** * Remove the context menu at a given level. * * @param level */ public void removeContextMenu(String level) { contextMenus.remove(level); } /** * Removes the tree listener. * * @param listener listener to remove. */ public void removeTreeListener(AdvanceTreeListener listener) { listeners.remove(listener); } /** * Sets the context menu for a given level. * * @param level the level to set * @param contextMenu the context menu object. */ public void setContextMenu(String level, TreePopupMenu contextMenu) { contextMenus.put(level, contextMenu); } /** * Enables or disables multi-selection. * * @param multiSelectionEnabled The multiSelectionEnabled to set. */ public void setMultiSelectionEnabled(boolean multiSelectionEnabled) { this.multiSelectionEnabled = multiSelectionEnabled; } public void setSelectedItem(TreeItem item) { setSelectedItem(item, false); } public void setSelectedItem(TreeItem item, boolean fireEvents) { if (item == null) { super.setSelectedItem(item, fireEvents); return; } if (fireEvents) { super.setSelectedItem(item, fireEvents); } else { processItemSelected(item, false); } } private TreeItem[] convertSelectedToArray() { TreeItem[] items = new TreeItem[selectedItems.size()]; for (int i = 0; i < items.length; i++) { items[i] = selectedItems.get(i); } return items; } private void init() { addStyleName("AdvanceTree"); initTreeListener(); } private void initTreeListener() { addSelectionHandler(new SelectionHandler<TreeItem>() { @Override public void onSelection(SelectionEvent<TreeItem> event) { processItemSelected(event.getSelectedItem(), true); } }); addOpenHandler(new OpenHandler<TreeItem>() { @Override public void onOpen(OpenEvent<TreeItem> event) { for (int i = 0; i < listeners.size(); i++) { AdvanceTreeListener listener = listeners.get(i); listener.onExpand(event.getTarget()); } } }); addCloseHandler(new CloseHandler<TreeItem>() { @Override public void onClose(CloseEvent<TreeItem> event) { for (int i = 0; i < listeners.size(); i++) { AdvanceTreeListener listener = listeners.get(i); listener.onCollapse(event.getTarget()); } } }); addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { if (event.getNativeEvent().getButton() == Event.BUTTON_RIGHT) { if (getSelectedItems() != null && getSelectedItems().length > 0) { String level = getLevel(getSelectedItems()[0]); TreePopupMenu menu = contextMenus.get(level); if (menu != null) { popup(getSelectedItems()[0], menu, level); } } } } }); addMouseUpHandler(new MouseUpHandler() { @Override public void onMouseUp(MouseUpEvent event) { if (event.getNativeEvent().getKeyCode() == Event.BUTTON_RIGHT) { } } }); } private void popup(TreeItem parent, TreePopupMenu menu, String level) { if (listeners.size() > 0) { TreeItem[] items = convertSelectedToArray(); for (int i = 0; i < listeners.size(); i++) { AdvanceTreeListener listener = listeners.get(i); listener.onPopup(level, menu, items); } } menu.setPopupPosition(parent.getAbsoluteLeft(), parent.getAbsoluteTop()); menu.show(); } private void processItemSelected(TreeItem item, boolean fireEvents) { String level = getLevel(item); if (processSelection(item, level) == false) { for (int i = 0; i < listeners.size(); i++) { AdvanceTreeListener listener = listeners.get(i); listener.onDeselect(item); } return; // an items has been unselected, no need to take any further action } if (fireEvents) { TreeItem[] items = convertSelectedToArray(); for (int i = 0; i < listeners.size(); i++) { AdvanceTreeListener listener = listeners.get(i); listener.onSelect(level, items); } } } private boolean processSelection(TreeItem item, String level) { if (multiSelectionEnabled) { if (selectedItems.contains(item)) { selectedItems.remove(item); item.getWidget().removeStyleName("AdvanceTree-SelectedItem"); return false; } if (!level.equals(selectedLevel)) { unselectItems(); } selectItem(item, level); return true; } else { unselectItems(); selectItem(item, level); return true; } } private void selectItem(TreeItem item, String level) { selectedItems.add(item); selectedLevel = level; item.getWidget().addStyleName("AdvanceTree-SelectedItem"); } private void unselectItems() { for (int i = 0; i < selectedItems.size(); i++) { TreeItem el = selectedItems.get(i); el.getWidget().removeStyleName("AdvanceTree-SelectedItem"); } selectedItems.clear(); selectedLevel = ""; } }