/* * Ext GWT - Ext for GWT * Copyright(c) 2007-2009, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license */ package com.extjs.gxt.ui.client.widget.treepanel; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.extjs.gxt.ui.client.data.ModelData; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.event.TreePanelEvent; import com.extjs.gxt.ui.client.store.TreeStore; import com.extjs.gxt.ui.client.util.KeyNav; import com.extjs.gxt.ui.client.util.Util; import com.extjs.gxt.ui.client.widget.selection.AbstractStoreSelectionModel; import com.extjs.gxt.ui.client.widget.treepanel.TreePanel.TreeNode; import com.google.gwt.user.client.Event; /** * <code>TreePanel</code> selection model. * * @param <M> the model type */ @SuppressWarnings("unchecked") public class TreePanelSelectionModel<M extends ModelData> extends AbstractStoreSelectionModel<M> implements Listener<TreePanelEvent> { protected TreePanel tree; protected TreeStore<M> treeStore; protected List<M> selectedPreRender; protected KeyNav<TreePanelEvent<M>> keyNav = new KeyNav<TreePanelEvent<M>>() { @Override public void onDown(TreePanelEvent<M> e) { onKeyDown(e); } @Override public void onLeft(TreePanelEvent<M> ce) { onKeyLeft(ce); } @Override public void onRight(TreePanelEvent<M> ce) { onKeyRight(ce); } @Override public void onUp(TreePanelEvent<M> e) { onKeyUp(e); } }; public void bindTree(TreePanel tree) { if (this.tree != null) { this.tree.removeListener(Events.OnMouseDown, this); keyNav.bind(null); bind(null); } this.tree = tree; if (tree != null) { tree.addListener(Events.OnMouseDown, this); keyNav.bind(tree); bind(tree.getStore()); this.treeStore = (TreeStore) tree.getStore(); } } @Override public void deselect(int index) { } @Override public void deselect(int start, int end) { } public void handleEvent(TreePanelEvent be) { int type = be.getEventTypeInt(); switch (type) { case Event.ONMOUSEDOWN: onMouseDown(be); break; } } @Override public boolean isSelected(M item) { return selected.contains(item); } @Override public void select(int start, int end, boolean keepExisting) { } /** * Selects the item below the selected item in the tree, intelligently walking * the nodes. */ public void selectNext() { M next = next(); if (next != null) { doSingleSelect(next, false); } } /** * Selects the item above the selected item in the tree, intelligently walking * the nodes. */ public void selectPrevious() { M prev = prev(); if (prev != null) { doSingleSelect(prev, false); } } protected void ensureExpanded(M model) { tree.setExpanded(treeStore.getParent(model), true); } protected void hookPreRender(M item, boolean select) { if (selectedPreRender == null) { selectedPreRender = new ArrayList<M>(); tree.addListener(Events.Render, new Listener<ComponentEvent>() { public void handleEvent(ComponentEvent be) { tree.removeListener(Events.Render, this); onRender(); } }); } if (select && !selectedPreRender.contains(item)) { selectedPreRender.add(item); } else if (!select) { selectedPreRender.remove(item); } } protected M next() { M sel = lastSelected; if (sel == null) { return null; } if (treeStore.getFirstChild(sel) != null && tree.isExpanded(sel)) { return treeStore.getFirstChild(sel); } else if (treeStore.getNextSibling(sel) != null) { return treeStore.getNextSibling(sel); } else if (treeStore.getParent(sel) != null) { M p = treeStore.getParent(sel); while (p != null) { if (treeStore.getNextSibling(p) != null) { return treeStore.getNextSibling(p); } p = treeStore.getParent(p); } } return null; } protected void onKeyDown(TreePanelEvent<M> e) { e.preventDefault(); M next = next(); if (next != null) { doSingleSelect(next, false); tree.scrollIntoView(next); } } protected void onKeyLeft(TreePanelEvent<M> ce) { if (lastSelected == null) { return; } if (!tree.isLeaf(lastSelected) && tree.isExpanded(lastSelected)) { tree.setExpanded(lastSelected, false); } else if (treeStore.getParent(lastSelected) != null) { doSingleSelect(treeStore.getParent(lastSelected), false); } } protected void onKeyRight(TreePanelEvent<M> ce) { if (lastSelected == null) { return; } if (!tree.isLeaf(lastSelected)) { if (!tree.isExpanded(lastSelected)) { tree.setExpanded(lastSelected, true); } } } protected void onKeyUp(TreePanelEvent<M> e) { e.preventDefault(); M prev = prev(); if (prev != null) { doSingleSelect(prev, false); tree.scrollIntoView(prev); } } protected void onRender() { if (selectedPreRender != null) { for (M item : selectedPreRender) { onSelectChange(item, true); } selectedPreRender = null; } } @Override protected void onSelectChange(M model, boolean select) { if (locked) return; if (!tree.isRendered()) { hookPreRender(model, select); return; } if (select) { ensureExpanded(model); } tree.getView().onSelectChange(model, select); } protected M prev() { M sel = lastSelected; if (sel == null) { return sel; } if (treeStore.getPreviousSibling(sel) != null) { M prev = treeStore.getPreviousSibling(sel); if ((!tree.isExpanded(prev) || treeStore.getChildCount(prev) < 1)) { return prev; } else { M lastChild = treeStore.getLastChild(prev); while (lastChild != null && treeStore.getChildCount(lastChild) > 0 && tree.isExpanded(lastChild)) { lastChild = treeStore.getLastChild(lastChild); } return lastChild; } } else if (treeStore.getParent(sel) != null) { return treeStore.getParent(sel); } return null; } private void onMouseDown(TreePanelEvent be) { if (be.getItem() == null) return; if (!tree.getView().isSelectableTarget(be.getItem(), be.getTarget())) { return; } M sel = (M) be.getItem(); switch (selectionMode) { case SIMPLE: if (isSelected(sel)) { deselect(sel); } else { doSelect(Util.createList(sel), true, false); } break; case SINGLE: doSingleSelect(sel, false); break; case MULTI: if (be.isShiftKey() && lastSelected != null) { List<M> items = new ArrayList<M>(); if (lastSelected == sel) { return; } TreeNode selNode = tree.findNode(lastSelected); TreeNode itemNode = tree.findNode(sel); if (selNode.element != null && itemNode.element != null) { if (selNode.element.getAbsoluteTop() < itemNode.element.getAbsoluteTop()) { M next = next(); while (next != null) { items.add(next); lastSelected = next; if (next == sel) break; next = next(); } } else { M prev = prev(); while (prev != null) { items.add(prev); lastSelected = prev; if (prev == sel) break; prev = prev(); } } doSelect(items, true, false); } } else if (isSelected(sel) && be.isControlKey()) { doDeselect(Arrays.asList(sel), false); } else { doSelect(Arrays.asList(sel), be.isControlKey(), false); } break; } } }