/*
* $Id$
*
* Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx.binding;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeSelectionModel;
import org.jdesktop.beansbinding.ext.BeanAdapterProvider;
import org.jdesktop.swingbinding.adapters.BeanAdapterBase;
/**
* @author Karl George Schaefer
* @author Shannon Hickey (for ideas from adapters package)
*/
public final class JTreeAdapterProvider implements BeanAdapterProvider {
private static final String SELECTED_ELEMENT_P = "selectedElement";
private static final String SELECTED_ELEMENTS_P = "selectedElements";
private static final String SELECTED_ELEMENT_UN_P = SELECTED_ELEMENT_P + "_UNWRAP_NODE";
private static final String SELECTED_ELEMENTS_UN_P = SELECTED_ELEMENTS_P + "_UNWRAP_NODE";
public final class Adapter extends BeanAdapterBase {
private JTree tree;
private Handler handler;
private Object cachedElementOrElements;
private Adapter(JTree tree, String property) {
super(property);
this.tree = tree;
}
private boolean isPlural() {
return property == SELECTED_ELEMENTS_P;
}
public Object getSelectedElement() {
return JTreeAdapterProvider.getSelectedElement(tree);
}
public Object getSelectedElement_UNWRAP_NODE() {
Object o = JTreeAdapterProvider.getSelectedElement(tree);
return unwrappedObject(o);
}
public List<Object> getSelectedElements() {
return JTreeAdapterProvider.getSelectedElements(tree);
}
public List<Object> getSelectedElements_UNWRAP_NODE() {
List<Object> objects = JTreeAdapterProvider.getSelectedElements(tree);
List<Object> unwrapped = new ArrayList<Object>(objects.size());
for (Object o : objects) {
unwrapped.add(unwrappedObject(o));
}
return unwrapped;
}
//why oh why is there no getUserObject method in the interface?!
private Object unwrappedObject(Object o) {
//possible to have null element
if (o == null) {
return o;
}
try {
Method m = o.getClass().getMethod("getUserObject");
return m.invoke(o);
} catch (SecurityException ignore) {
//just return o
} catch (NoSuchMethodException ignore) {
//just return o
} catch (IllegalAccessException ignore) {
//just return o
} catch (InvocationTargetException ignore) {
//just return o
}
return o;
}
protected void listeningStarted() {
handler = new Handler();
cachedElementOrElements = isPlural() ? getSelectedElements() : JTreeAdapterProvider
.getSelectedElement(tree);
tree.addPropertyChangeListener("selectionModel", handler);
tree.getSelectionModel().addTreeSelectionListener(handler);
}
protected void listeningStopped() {
tree.getSelectionModel().removeTreeSelectionListener(handler);
tree.removePropertyChangeListener("selectionModel", handler);
cachedElementOrElements = null;
handler = null;
}
private class Handler implements TreeSelectionListener, PropertyChangeListener {
private void treeSelectionChanged() {
Object oldElementOrElements = cachedElementOrElements;
cachedElementOrElements = getSelectedElements();
firePropertyChange(oldElementOrElements, cachedElementOrElements);
}
public void valueChanged(TreeSelectionEvent e) {
treeSelectionChanged();
}
public void propertyChange(PropertyChangeEvent pce) {
((TreeSelectionModel) pce.getOldValue()).removeTreeSelectionListener(handler);
((TreeSelectionModel) pce.getNewValue()).addTreeSelectionListener(handler);
treeSelectionChanged();
}
}
}
private static List<Object> getSelectedElements(JTree tree) {
assert tree != null;
TreeSelectionModel selectionModel = tree.getSelectionModel();
int min = selectionModel.getMinSelectionRow();
int max = selectionModel.getMaxSelectionRow();
if (min < 0 || max < 0) {
return new ArrayList<Object>(0);
}
ArrayList<Object> elements = new ArrayList<Object>(max - min + 1);
for (int i = min; i <= max; i++) {
if (selectionModel.isRowSelected(i)) {
elements.add(getElement(tree, i));
}
}
return elements;
}
private static Object getSelectedElement(JTree tree) {
assert tree != null;
int index = tree.getSelectionModel().getLeadSelectionRow();
index = tree.getSelectionModel().isRowSelected(index) ? index : tree.getSelectionModel()
.getMinSelectionRow();
if (index == -1) {
return null;
}
return getElement(tree, index);
}
private static Object getElement(JTree tree, int index) {
return tree.getPathForRow(index).getLastPathComponent();
}
public boolean providesAdapter(Class<?> type, String property) {
if (!JTree.class.isAssignableFrom(type)) {
return false;
}
property = property.intern();
return property == SELECTED_ELEMENT_P
|| property == SELECTED_ELEMENT_UN_P
|| property == SELECTED_ELEMENTS_P
|| property == SELECTED_ELEMENTS_UN_P;
}
public Object createAdapter(Object source, String property) {
if (!providesAdapter(source.getClass(), property)) {
throw new IllegalArgumentException();
}
return new Adapter((JTree) source, property);
}
public Class<?> getAdapterClass(Class<?> type) {
return JTree.class.isAssignableFrom(type) ? JTreeAdapterProvider.Adapter.class : null;
}
}