/*
* Ext GWT 2.2.4 - Ext for GWT
* Copyright(c) 2007-2010, 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.Style.SelectionMode;
import com.extjs.gxt.ui.client.data.ModelData;
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.StoreEvent;
import com.extjs.gxt.ui.client.store.StoreListener;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.store.TreeStoreEvent;
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", "rawtypes"})
public class TreePanelSelectionModel<M extends ModelData> extends AbstractStoreSelectionModel<M> implements
Listener<TreePanelEvent> {
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);
}
};
protected TreePanel tree;
protected TreeStore<M> treeStore;
public TreePanelSelectionModel() {
storeListener = new StoreListener<M>() {
@Override
public void storeAdd(StoreEvent<M> se) {
TreeStoreEvent<M> tse = (TreeStoreEvent) se;
onAdd(tse.getChildren());
}
@Override
public void storeClear(StoreEvent<M> se) {
onClear(se);
}
@Override
public void storeRemove(StoreEvent<M> se) {
TreeStoreEvent<M> tse = (TreeStoreEvent) se;
onRemove(tse.getChild());
for (M child : tse.getChildren()) {
onRemove(child);
}
}
@Override
public void storeUpdate(StoreEvent<M> se) {
onUpdate(se.getModel());
}
};
}
public void bindTree(TreePanel tree) {
if (this.tree != null) {
this.tree.removeListener(Events.OnMouseDown, this);
this.tree.removeListener(Events.OnClick, this);
this.tree.removeListener(Events.Render, this);
keyNav.bind(null);
bind(null);
this.treeStore = null;
}
this.tree = tree;
if (tree != null) {
tree.addListener(Events.OnMouseDown, this);
tree.addListener(Events.OnClick, this);
tree.addListener(Events.Render, 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 tpe) {
if (tpe.getType() == Events.Render) {
refresh();
} else {
int type = tpe.getEventTypeInt();
switch (type) {
case Event.ONMOUSEDOWN:
onMouseDown(tpe);
break;
case Event.ONCLICK:
onMouseClick(tpe);
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 M next() {
M sel = lastSelected;
if (sel == null) {
return null;
}
M first = treeStore.getFirstChild(sel);
if (first != null && tree.isExpanded(sel)) {
return first;
} else {
M nextSibling = treeStore.getNextSibling(sel);
if (nextSibling != null) {
return nextSibling;
} else {
M p = treeStore.getParent(sel);
while (p != null) {
nextSibling = treeStore.getNextSibling(p);
if (nextSibling != null) {
return nextSibling;
}
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) {
ce.preventDefault();
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) {
ce.preventDefault();
if (!tree.isLeaf(lastSelected) && !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 onMouseClick(TreePanelEvent e) {
if (isLocked()) {
return;
}
if (selectionMode == SelectionMode.MULTI) {
M sel = (M) e.getItem();
if (isSelected(sel) && getSelectedItems().size() > 1) {
if (!e.isControlKey() && !e.isShiftKey()) {
select(Arrays.asList(sel), false);
}
}
}
}
protected void onMouseDown(TreePanelEvent be) {
if (be.getItem() == null) return;
if (!tree.getView().isSelectableTarget(be.getItem(), be.getTarget())) {
return;
}
if (be.isRightClick() && isSelected((M) be.getItem())) {
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 (isSelected(sel) && !be.isControlKey() && !be.isShiftKey()) {
return;
}
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 (be.isControlKey() && isSelected(sel)) {
doDeselect(Arrays.asList(sel), false);
} else {
doSelect(Arrays.asList(sel), be.isControlKey(), false);
}
break;
}
}
@Override
protected void onSelectChange(M model, boolean select) {
tree.getView().onSelectChange(model, select);
}
protected M prev() {
M sel = lastSelected;
if (sel == null) {
return sel;
}
M prev = treeStore.getPreviousSibling(sel);
if (prev != null) {
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 {
M parent = treeStore.getParent(sel);
if (parent != null) {
return parent;
}
}
return null;
}
}