/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.streamsim.commonsgui; import java.beans.PropertyEditor; import java.lang.reflect.InvocationTargetException; import java.util.LinkedHashSet; import java.util.Set; import javax.swing.Action; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Node.PropertySet; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.Lookup; /** * * @author Matteo Di Giovinazzo */ public abstract class AbstractCheckableNode extends AbstractNode { public enum SelectedState { // module / all modules in cluster selected FULL_SELECTED, // only for clusters - some but not all modules are enabled PART_SELECTED, // module / whole cluster disabled UNSELECTED }; public static final String PROP_SELECTION = "selection"; // NOI18N public static final SelectedProperty SELECTED_PROP_TEMPLATE = new SelectedProperty(null); private SelectedState state = SelectedState.UNSELECTED; public AbstractCheckableNode(Children ch) { this(ch, Lookup.EMPTY); } public AbstractCheckableNode(Children ch, Lookup lkp) { super(ch, lkp); } public abstract T getKEY(); public void setSelected(boolean s) { setState(s ? SelectedState.FULL_SELECTED : SelectedState.UNSELECTED, true); } public boolean isSelected() { return state != SelectedState.UNSELECTED; } @Override protected final Sheet createSheet() { Sheet sheet1 = super.createSheet(); Sheet.Set select = Sheet.createPropertiesSet(); Set> np = new LinkedHashSet>(); np.add(new SelectedProperty(this)); select.put(np.toArray(new PropertySupport[np.size()])); Sheet sheet2 = createSheet0(); Sheet ret = Sheet.createDefault(); for (PropertySet s : sheet1.toArray()) { Sheet.Set set = new Sheet.Set(); set.put(s.getProperties()); ret.put(set); } ret.put(select); for (PropertySet s : sheet2.toArray()) { Sheet.Set set = new Sheet.Set(); set.put(s.getProperties()); ret.put(set); } return ret; } protected Sheet createSheet0() { return Sheet.createDefault(); }; @Override public Action[] getActions(boolean context) { return new Action[0]; } public SelectedState getState() { return state; } private void setState(SelectedState s, boolean propagate) { if(state == s){ return; } SelectedState oldState = state; state = s; //refresh me firePropertyChange(PROP_SELECTION, oldState, state); if (propagate) { //refresh children SelectedState newChildState = (s == SelectedState.PART_SELECTED) ? null : s; if (newChildState != null) { final Node[] nodes = getChildren().getNodes(true); for (Node nn : nodes) { if (nn instanceof AbstractCheckableNode) { AbstractCheckableNode en = (AbstractCheckableNode) nn; // #70724: checking/unchecking cluster node checks/unchecks all children en.setState(newChildState, true); // en.firePropertyChange(PROP_SELECTION, null, null); } } } } //refresh parent Node n = getParentNode(); if (n instanceof AbstractCheckableNode) { // assert s != SelectedState.PART_SELECTED : "Module node should not be passed PART_SELECTED state"; AbstractCheckableNode par = (AbstractCheckableNode) n; par.updateChildrenState(); // par.firePropertyChange(PROP_SELECTION, null, null); } } private void updateChildrenState() { boolean allSelected = true; boolean allUnselected = true; for (Node nn : getChildren().getNodes(true)) { if (nn instanceof AbstractCheckableNode) { AbstractCheckableNode en = (AbstractCheckableNode) nn; allSelected &= (en.getState() == SelectedState.FULL_SELECTED); allUnselected &= (en.getState() == SelectedState.UNSELECTED); if (!allSelected && !allUnselected) { break; } } } if (allSelected) { setState(SelectedState.FULL_SELECTED, false); } else if (allUnselected) { setState(SelectedState.UNSELECTED, false); } else { setState(SelectedState.PART_SELECTED, false); } } public static final class SelectedProperty extends PropertySupport.ReadWrite { private AbstractCheckableNode node; private PropertyEditor editor; public SelectedProperty(AbstractCheckableNode node) { super(PROP_SELECTION, Boolean.TYPE, "Selected", ""); this.node = node; setValue("ComparableColumnTTV", Boolean.TRUE); } public void setValue(Boolean val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (node != null) { node.setSelected(val); } } public Boolean getValue() throws IllegalAccessException, InvocationTargetException { if (node != null) { org.openide.nodes.Children ch = node.getChildren(); if (ch == Children.LEAF) { return node.isSelected(); } else if (node.getState() == SelectedState.PART_SELECTED) { return null; } else { return node.isSelected(); } } return false; } @Override public PropertyEditor getPropertyEditor() { if (editor == null) { editor = super.getPropertyEditor(); //editor = new BoolEditor(); } return editor; } } }