package org.esa.snap.rcp.nodes; import org.esa.snap.core.datamodel.ProductNode; import org.esa.snap.core.datamodel.RasterDataNode; import org.openide.explorer.propertysheet.ExPropertyEditor; import org.openide.explorer.propertysheet.PropertyEnv; import javax.swing.DefaultListModel; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListSelectionModel; import javax.swing.border.EmptyBorder; import java.awt.BorderLayout; import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyEditorSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.util.ArrayList; import java.util.HashMap; import java.util.stream.Collectors; import java.util.stream.Stream; /** * A property editor for selected rasters. * * @author Norman Fomferra */ class RastersPropertyEditor extends PropertyEditorSupport implements ExPropertyEditor, VetoableChangeListener { static final String SEPARATOR = ","; private RasterDataNode[] validNodes; private CustomEditor customEditor; public RastersPropertyEditor(RasterDataNode... validNodes) { this.validNodes = validNodes; } @Override public String getAsText() { RasterDataNode[] value = (RasterDataNode[]) getValue(); if (value == null) { return ""; } return Stream.of(value).map(ProductNode::getName).collect(Collectors.joining(SEPARATOR + " ")); } @Override public void setAsText(String text) throws IllegalArgumentException { if (text == null || text.trim().isEmpty()) { setValue(new RasterDataNode[0]); return; } HashMap<String, RasterDataNode> validNames = getValidNodeNames(); ArrayList<RasterDataNode> nodes = new ArrayList<>(); String[] names = text.split(SEPARATOR); for (String name : names) { name = name.trim(); RasterDataNode node = validNames.get(name); if (node == null) { throw new IllegalArgumentException("Illegal entry '" + name + "'!"); } nodes.add(node); } setValue(nodes.toArray(new RasterDataNode[nodes.size()])); } @Override public boolean supportsCustomEditor() { return true; } @Override public Component getCustomEditor() { customEditor = new CustomEditor(); //System.out.println(":::::::::::::::: getCustomEditor: customEditor = " + customEditor); customEditor.setSelectedNodes((RasterDataNode[]) getValue()); return customEditor; } @Override public void attachEnv(PropertyEnv propertyEnv) { //System.out.println(":::::::::::::::: attachEnv: propertyEnv = " + propertyEnv); propertyEnv.addVetoableChangeListener(this); propertyEnv.setState(PropertyEnv.STATE_NEEDS_VALIDATION); } @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { //System.out.println(":::::::::::::::: vetoableChange: evt = " + evt); //System.out.println(":::::::::::::::: vetoableChange: customEditor = " + customEditor); if (PropertyEnv.PROP_STATE.equals(evt.getPropertyName())) { if (customEditor != null) { RasterDataNode[] selectedNodes = customEditor.getSelectedNodes(); String collect = Stream.of(selectedNodes).map(n -> n.getName()).collect(Collectors.joining("; ")); //System.out.println(":::::::::::::::: vetoableChange: collect = " + collect); if (PropertyEnv.STATE_VALID.equals(evt.getNewValue())) { try { setValue(selectedNodes); } catch (IllegalArgumentException e) { throw new PropertyVetoException(e.getMessage(), evt); } } customEditor = null; } } } private HashMap<String, RasterDataNode> getValidNodeNames() { HashMap<String, RasterDataNode> validNames = new HashMap<>(); for (RasterDataNode node : validNodes) { validNames.put(node.getName(), node); } return validNames; } private class CustomEditor extends JPanel { private final JList<String> list; private final DefaultListModel<String> listModel; public CustomEditor() { super(new BorderLayout(4, 4)); setBorder(new EmptyBorder(8, 8, 8, 8)); listModel = new DefaultListModel<>(); list = new JList<>(listModel); list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); JScrollPane scrollPane = new JScrollPane(list); add(new JLabel("Available rasters:"), BorderLayout.NORTH); add(scrollPane, BorderLayout.CENTER); } public RasterDataNode[] getSelectedNodes() throws PropertyVetoException { HashMap<String, RasterDataNode> validNodeNames = getValidNodeNames(); ArrayList<RasterDataNode> nodes = new ArrayList<>(); int[] selectedIndices = list.getSelectedIndices(); for (int index : selectedIndices) { String name = listModel.get(index); RasterDataNode node = validNodeNames.get(name); if (node != null) { nodes.add(node); } } return nodes.toArray(new RasterDataNode[nodes.size()]); } public void setSelectedNodes(RasterDataNode[] selectedNodes) { HashMap<RasterDataNode, Integer> indexMap = new HashMap<>(); listModel.clear(); for (int i = 0; i < validNodes.length; i++) { RasterDataNode node = validNodes[i]; listModel.addElement(node.getName()); indexMap.put(node, i); } ArrayList<Integer> indexList = new ArrayList<>(); for (RasterDataNode selectedNode : selectedNodes) { Integer index = indexMap.get(selectedNode); if (index != null) { indexList.add(index); } } int[] indices = new int[indexList.size()]; for (int i = 0; i < indices.length; i++) { indices[i] = indexList.get(i); } list.setSelectedIndices(indices); } } }