/******************************************************************************* * 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); } }