/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.esa.snap.rcp.nodes; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.datamodel.ProductData; import org.esa.snap.core.datamodel.ProductNode; import org.esa.snap.core.datamodel.ProductNodeGroup; import org.esa.snap.rcp.SnapApp; import org.esa.snap.rcp.actions.file.CloseProductAction; import org.openide.awt.UndoRedo; import org.openide.nodes.Node; import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.WeakListeners; import javax.swing.Action; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.text.ParseException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; import java.util.stream.Stream; import static org.esa.snap.rcp.nodes.PNNodeSupport.*; /** * A node that represents a {@link Product} (=P). * Every {@code PNode} holds a dedicated undo/redo context. * * @author Norman */ public class PNode extends PNNode<Product> implements PreferenceChangeListener { private final PContent group; public PNode(Product product) { this(product, new PContent()); } private PNode(Product product, PContent group) { super(product, group); this.group = group; group.node = this; setDisplayName(product.getDisplayName()); setShortDescription(product.getDescription()); setIconBaseWithExtension("org/esa/snap/rcp/icons/RsProduct16.gif"); Preferences preferences = SnapApp.getDefault().getPreferences(); preferences.addPreferenceChangeListener(WeakListeners.create(PreferenceChangeListener.class, this, preferences)); } public Product getProduct() { return getProductNode(); } @Override public UndoRedo getUndoRedo() { return SnapApp.getDefault().getUndoManager(getProduct()); } @Override public boolean canDestroy() { return false; } @Override public void destroy() throws IOException { new CloseProductAction(Collections.singletonList(getProduct())).execute(); } @Override public Action[] getActions(boolean context) { return PNNodeSupport.getContextActions(getProductNode()); } @Override public Action getPreferredAction() { //Define the action that will be invoked //when the user double-clicks on the node: return super.getPreferredAction(); } @Override public void preferenceChange(PreferenceChangeEvent evt) { String key = evt.getKey(); if (GroupByNodeTypeAction.PREFERENCE_KEY.equals(key)) { group.refresh(); } } @Override public PropertySet[] getPropertySets() { Sheet.Set set = new Sheet.Set(); set.setDisplayName("Product Properties"); set.put(new PropertySupport.ReadOnly<File>("fileLocation", File.class, "File", "File location") { @Override public File getValue() { return getProduct().getFileLocation(); } }); set.put(new PropertySupport.ReadWrite<String>("productType", String.class, "Product Type", "The product type identifier") { @Override public String getValue() { return getProduct().getProductType(); } @Override public void setValue(String newValue) throws IllegalArgumentException { String oldValue = getProduct().getProductType(); performUndoableProductNodeEdit("Edit Product Type", getProduct(), node -> node.setProductType(newValue), node -> node.setProductType(oldValue)); } }); set.put(new PropertySupport.ReadWrite<String>("startTime", String.class, "Sensing Start Time", "The product's sensing start time") { @Override public String getValue() { ProductData.UTC startTime = getProduct().getStartTime(); return startTime != null ? startTime.format() : ""; } @Override public void setValue(String s) throws IllegalArgumentException { ProductData.UTC oldValue = getProduct().getStartTime(); try { ProductData.UTC newValue = ProductData.UTC.parse(s); performUndoableProductNodeEdit("Edit Sensing Start Time", getProduct(), node -> node.setStartTime(newValue), node -> node.setStartTime(oldValue)); } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage()); } } }); set.put(new PropertySupport.ReadWrite<String>("endTime", String.class, "Sensing Stop Time", "The product's sensing stop time") { @Override public String getValue() { ProductData.UTC endTime = getProduct().getEndTime(); return endTime != null ? endTime.format() : ""; } @Override public void setValue(String s) throws IllegalArgumentException { Product product = getProduct(); ProductData.UTC oldValue = product.getEndTime(); try { ProductData.UTC newValue = ProductData.UTC.parse(s); performUndoableProductNodeEdit("Edit Sensing Stop Time", product, node -> node.setEndTime(newValue), node -> node.setEndTime(oldValue)); } catch (ParseException e) { throw new IllegalArgumentException(e.getMessage()); } } }); set.put(new PropertySupport.ReadWrite<String>("bandGrouping", String.class, "Band Grouping", "The product's band grouping") { @Override public String getValue() { final Product.AutoGrouping autoGrouping = getProduct().getAutoGrouping(); if (autoGrouping == null) { return ""; } else { return autoGrouping.toString(); } } @Override public void setValue(String s) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Product.AutoGrouping oldValue = getProduct().getAutoGrouping(); Product.AutoGrouping newValue = Product.AutoGrouping.parse(s); performUndoableProductNodeEdit("Edit Band-Grouping", getProduct(), node -> node.setAutoGrouping(newValue), node -> node.setAutoGrouping(oldValue)); } }); includeAbstractedMetadata(set); return Stream.concat(Stream.of(super.getPropertySets()), Stream.of(set)).toArray(PropertySet[]::new); } private void includeAbstractedMetadata(final Sheet.Set set) { final MetadataElement root = getProduct().getMetadataRoot(); if (root != null) { final MetadataElement absRoot = root.getElement("Abstracted_Metadata"); if (absRoot != null) { set.put(new PropertySupport.ReadOnly<String>("mission", String.class, "Mission", "Earth Observation Mission") { @Override public String getValue() { return absRoot.getAttributeString("mission"); } }); set.put(new PropertySupport.ReadOnly<String>("mode", String.class, "Acquisition Mode", "Sensor Acquisition Mode") { @Override public String getValue() { return absRoot.getAttributeString("ACQUISITION_MODE"); } }); set.put(new PropertySupport.ReadOnly<String>("pass", String.class, "Pass", "Orbital Pass") { @Override public String getValue() { return absRoot.getAttributeString("pass"); } }); set.put(new PropertySupport.ReadOnly<String>("track", String.class, "Track", "Relative Orbit") { @Override public String getValue() { return absRoot.getAttributeString("REL_ORBIT"); } }); set.put(new PropertySupport.ReadOnly<String>("orbit", String.class, "Orbit", "Absolute Orbit") { @Override public String getValue() { return absRoot.getAttributeString("ABS_ORBIT"); } }); } } } private boolean isGroupByNodeType() { return SnapApp.getDefault().getPreferences().getBoolean(GroupByNodeTypeAction.PREFERENCE_KEY, GroupByNodeTypeAction.PREFERENCE_DEFAULT_VALUE); } /* @Override public NewType[] getNewTypes() { return new NewType[] { new NewType() { @Override public String getName() { return "Calculated Band"; } @Override public void create() throws IOException { } }, new NewType() { @Override public String getName() { return "Filtered Band"; } @Override public void create() throws IOException { } } }; } */ /** * A child factory for nodes below a {@link PNode} that holds a {@link Product}. * * @author Norman */ static class PContent extends PNGroupBase<Object> { PNode node; @Override protected boolean createKeys(List<Object> list) { Product product = node.getProduct(); ProductNodeGroup<MetadataElement> metadataElementGroup = product.getMetadataRoot().getElementGroup(); if (node.isGroupByNodeType()) { if (metadataElementGroup != null) { list.add(new PNGGroup.ME(metadataElementGroup)); } if (product.getIndexCodingGroup().getNodeCount() > 0) { list.add(new PNGGroup.IC(product.getIndexCodingGroup())); } if (product.getFlagCodingGroup().getNodeCount() > 0) { list.add(new PNGGroup.FC(product.getFlagCodingGroup())); } if (product.getVectorDataGroup().getNodeCount() > 0) { list.add(new PNGGroup.VDN(product.getVectorDataGroup())); } if (product.getTiePointGridGroup().getNodeCount() > 0) { list.add(new PNGroupingGroup.TPG(product.getTiePointGridGroup())); } if (product.getQuicklookGroup().getNodeCount() > 0) { list.add(new PNGGroup.QL(product.getQuicklookGroup())); } if (product.getBandGroup().getNodeCount() > 0) { list.add(new PNGroupingGroup.B(product.getBandGroup())); } if (product.getMaskGroup().getNodeCount() > 0) { list.add(new PNGroupingGroup.M(product.getMaskGroup())); } } else { if (metadataElementGroup != null) { list.addAll(Arrays.asList(metadataElementGroup.toArray())); } list.addAll(Arrays.asList(product.getIndexCodingGroup().toArray())); list.addAll(Arrays.asList(product.getFlagCodingGroup().toArray())); list.addAll(Arrays.asList(product.getVectorDataGroup().toArray())); list.addAll(Arrays.asList(product.getTiePointGridGroup().toArray())); list.addAll(Arrays.asList(product.getQuicklookGroup().toArray())); list.addAll(Arrays.asList(product.getBandGroup().toArray())); list.addAll(Arrays.asList(product.getMaskGroup().toArray())); } return true; } @Override protected Node createNodeForKey(Object key) { if (key instanceof ProductNode) { return PNNode.create((ProductNode) key); } else { return new PNGroupNode((PNGroup) key); } } } }