/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.ui.attribute.adapter;
import java.util.ArrayList;
import java.util.Iterator;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.jboss.tools.common.model.ui.viewers.xpl.CheckStateChangedEvent;
import org.jboss.tools.common.model.ui.viewers.xpl.ICheckStateListener;
import org.jboss.tools.common.model.ui.viewers.xpl.ICheckable;
import org.jboss.tools.common.model.util.EclipseResourceUtil;
/**
* @author au
*/
public class CheckTreeAdapter extends DefaultValueAdapter implements ITreeContentProvider {
protected CheckTree tree;
protected CheckLabelProvider labelProvider;
protected ISelectionChangedListener selectionChangedListener;
private Image IMAGE_CHECK = EclipseResourceUtil.getImage("images/common/check.gif"); //$NON-NLS-1$
private Image IMAGE_UNCHECK = EclipseResourceUtil.getImage("images/common/uncheck.gif"); //$NON-NLS-1$
private Image IMAGE_HALFCHECK = EclipseResourceUtil.getImage("images/common/halfcheck.gif"); //$NON-NLS-1$
public class CheckTree implements ICheckable {
private ArrayList<ICheckStateListener> listeners = new ArrayList<ICheckStateListener>();
private ArrayList<CheckItem> roots;
public CheckTree() {
roots = new ArrayList<CheckItem>();
}
public void dispose() {
listeners.clear();
}
public CheckItem[] getRoot() {
return (CheckItem[])roots.toArray(new CheckItem[roots.size()]);
}
public void addRoot(CheckItem child) {
roots.add(child);
child.setTree(this);
}
public void removeRoot(CheckItem child) {
roots.remove(roots.indexOf(child));
child.setTree(null);
}
public boolean hasChildren(CheckItem element) {
return (roots.size()>0);
}
public void addCheckStateListener(ICheckStateListener listener) {
listeners.add(listener);
}
public int getState(Object element) {
if(element == null) return 0;
return ((CheckItem)element).getState();
}
public void removeCheckStateListener(ICheckStateListener listener) {
listeners.remove(listener);
}
public boolean setState(Object element, int state) {
CheckItem item = ((CheckItem)element);
int oldState = item.getState();
item.setState(state);
if (oldState!=state) {
this.fireStateChanged(item);
}
return Boolean.TRUE.booleanValue();
}
protected void fireStateChanged(CheckItem item) {
Iterator i = listeners.iterator();
CheckStateChangedEvent event = new CheckStateChangedEvent(this, item, item.getState());
while (i.hasNext()) {
((ICheckStateListener)i.next()).checkStateChanged(event);
}
}
public void toggle(Object element) {
}
}
public class CheckItem implements ICheckable {
private ArrayList<CheckItem> childs;
private CheckItem parent;
private int state;
private int userState;
private String name;
private CheckTree tree;
private Object data;
private CheckItem() {}
public CheckItem(String name, int state) {
childs = new ArrayList<CheckItem>();
parent = null;
this.name = name;
this.state = state;
this.userState = state;
}
public CheckItem(String name, int state, CheckItem parent) {
childs = new ArrayList<CheckItem>();
//this.parent = parent;
this.name = name;
this.state = state;
this.userState = state;
if (parent!=null) {
parent.addChild(this);
}
}
public CheckItem(String name, int state, Object data) {
childs = new ArrayList<CheckItem>();
parent = null;
this.name = name;
this.state = state;
this.data = data;
this.userState = state;
}
public CheckItem(String name, int state, Object data, CheckItem parent) {
childs = new ArrayList<CheckItem>();
//this.parent = parent;
this.name = name;
this.state = state;
this.data = data;
this.userState = state;
if (parent!=null) {
parent.addChild(this);
}
}
public void addChild(CheckItem child) {
childs.add(child);
child.setParent(this);
if (childs.size()==1) {
this.setState(child.getState());
}
if (this.getState()!=ICheckable.STATE_HALFCHECK && this.getState() != child.getState()) {
this.setState(ICheckable.STATE_HALFCHECK);
}
}
public void removeChild(CheckItem child) {
childs.remove(childs.indexOf(child));
child.setParent(null);
}
public CheckItem[] getChildrens() {
return childs.toArray(new CheckItem[childs.size()]);
}
public boolean hasChildren() {
return (childs.size()>0);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public CheckItem getParent() {
return parent;
}
public void setParent(CheckItem parent) {
this.parent = parent;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public void addCheckStateListener(ICheckStateListener listener) {
}
public int getState(Object element) {
if(element == null) return state;
if (this.tree!=null) return tree.getState(element);
return ICheckable.STATE_UNCHECK;
}
public void removeCheckStateListener(ICheckStateListener listener) {
}
public boolean setState(Object element, int state) {
if (this.tree!=null) return tree.setState(element, state);
// else
this.setState(state);
return Boolean.FALSE.booleanValue();
}
public CheckTree getTree() {
return tree;
}
public void setTree(CheckTree tree) {
this.tree = tree;
if (this.hasChildren()) {
Iterator<CheckItem> i = childs.iterator();
while (i.hasNext()) i.next().setTree(tree);
}
}
protected void toState(int nextState) {
if (nextState == ICheckable.STATE_CHECK) {
this.setState(this, ICheckable.STATE_CHECK);
if (this.hasChildren()) {
CheckItem[] childs = this.getChildrens();
for (int i=0;i<childs.length;++i) childs[i].toState(nextState);
}
} else if (nextState == ICheckable.STATE_UNCHECK) {
this.setState(this, ICheckable.STATE_UNCHECK);
if (this.hasChildren()) {
CheckItem[] childs = this.getChildrens();
for (int i=0;i<childs.length;++i) childs[i].toState(nextState);
}
} else {
if (!this.hasChildren()) {
this.setState(this, this.getUserState());
} else {
this.setUserState(nextState);
if (this.hasChildren()) {
CheckItem[] childs = this.getChildrens();
for (int i=0;i<childs.length;++i) childs[i].toState(nextState);
}
boolean skipHalf = Boolean.TRUE.booleanValue();
CheckItem[] childs = this.getChildrens();
int childUserState = childs[0].getUserState();
for (int i=1;i<childs.length;++i) {
if (childs[i].getUserState() == ICheckable.STATE_HALFCHECK) {
skipHalf = Boolean.FALSE.booleanValue();
break;
}
if (childUserState != childs[i].getUserState()) {
skipHalf = Boolean.FALSE.booleanValue();
break;
}
}
if (skipHalf) {
this.setState(this, childUserState);
} else {
this.setState(this, nextState);
}
}
}
}
public void toggle(Object element) {
if (element==this) {
// message from control about user change this node
// 1. get next state (to check, to uncheck, or to user state)
int nextState = getNextState();
// 2. notify self and children
toState(nextState);
Iterator i = this.childs.iterator();
while (i.hasNext()) ((CheckItem)i.next()).toState(nextState);
// 3. notify parent
if (parent!=null) {
parent.toggle(element);
}
} else {
// message from child about user change child node
// 1. copy state to user state for children
CheckItem item;
Iterator i = this.childs.iterator();
while (i.hasNext()) {
item = (CheckItem)i.next();
item.setUserState(item.getState());
}
// 2. set new state for self
CheckItem[] childs = this.getChildrens();
int childState = childs[0].getState();
for (int j=1;j<childs.length;++j) {
if (childState != childs[j].getState()) {
childState = ICheckable.STATE_HALFCHECK;
break;
}
}
this.setState(this, childState);
// 3. notify parent
if (parent!=null) parent.toggle(element);
}
}
private int getNextState() {
if (this.getState() == ICheckable.STATE_UNCHECK) {
// from uncheck to half-check or check
if (this.hasChildren()) {
boolean skipHalf = Boolean.TRUE.booleanValue();
if (this.hasChildren()) {
CheckItem[] childs = this.getChildrens();
int childUserState = childs[0].getUserState();
for (int i=1;i<childs.length;++i) {
if (childs[i].getUserState() == ICheckable.STATE_HALFCHECK) {
skipHalf = Boolean.FALSE.booleanValue();
break;
}
if (childUserState != childs[i].getUserState()) {
skipHalf = Boolean.FALSE.booleanValue();
break;
}
}
}
if (skipHalf) {
return ICheckable.STATE_CHECK;
} else {
return ICheckable.STATE_HALFCHECK;
}
} else {
return ICheckable.STATE_CHECK;
}
} else if (this.getState() == ICheckable.STATE_HALFCHECK) {
// from half-check to check
return ICheckable.STATE_CHECK;
} else {
// from check to unckeck
return ICheckable.STATE_UNCHECK;
}
}
public boolean hasChildUserState() {
Iterator i = this.childs.iterator();
while (i.hasNext()) {
if (((CheckItem)i.next()).hasChildUserState()) return Boolean.TRUE.booleanValue();
}
return (this.state != this.userState);
}
public int getUserState() {
return userState;
}
public void setUserState(int userState) {
this.userState = userState;
/*
if (!this.hasChildren()) {
if (parent!=null) {
parent.setUserState(userState);
}
} else {
// notify about user change same node
// 1. copy from state to user state
Iterator i = this.childs.iterator();
while (i.hasNext()) {
((CheckItem)i.next()).setUserState(((CheckItem)i.next()).getState());
}
}
*/
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
protected class CheckLabelProvider extends LabelProvider {
/**
* Tree style SWT.CHECK is used instead.
public Image getImage(Object element) {
if (((CheckItem)element).getState() == ICheckable.STATE_UNCHECK) {
return IMAGE_UNCHECK;
} else if (((CheckItem)element).getState() == ICheckable.STATE_CHECK) {
return IMAGE_CHECK;
} else {
return IMAGE_HALFCHECK;
}
}
*/
public String getText(Object element) {
return ((CheckItem)element).getName();
}
}
public CheckTreeAdapter() {
tree = new CheckTree();
tree.addRoot(new CheckItem("Item1", ICheckable.STATE_CHECK));
tree.addRoot(new CheckItem("Item2", ICheckable.STATE_UNCHECK));
tree.addRoot(new CheckItem("Item3", ICheckable.STATE_HALFCHECK));
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(Object parentElement) {
return ((CheckItem)parentElement).getChildrens();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(Object element) {
return ((CheckItem)element).getParent();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(Object element) {
return ((CheckItem)element).hasChildren();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
return tree.getRoot();
}
public void dispose() {
super.dispose();
if (tree!=null) tree.dispose();
if (labelProvider!=null) labelProvider.dispose();
selectionChangedListener = null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object getAdapter(Class adapter) {
if (adapter == ILabelProvider.class) {
if (labelProvider==null) labelProvider = new CheckLabelProvider();
return labelProvider;
}
if (adapter == ITreeContentProvider.class) {
return this;
}
//if (adapter == )
return super.getAdapter(adapter);
}
}