/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package org.esa.snap.ui.product;
import org.esa.snap.core.datamodel.Band;
import org.esa.snap.core.datamodel.Mask;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.TiePointGrid;
import org.esa.snap.core.dataop.barithm.BandArithmetic;
import org.esa.snap.core.jexp.Namespace;
import org.esa.snap.core.jexp.impl.ParserImpl;
import org.esa.snap.core.util.PropertyMap;
import org.esa.snap.ui.ExpressionPane;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* An expression pane to be used in conjunction with {@link Product}s in order to edit and assemble band arithmetic expressions.
*/
public class ProductExpressionPane extends ExpressionPane {
private Product[] products;
private Product currentProduct;
private Product targetProduct;
private JComboBox<String> productBox;
private JList<String> nodeList;
private JCheckBox inclBandsCheck;
private JCheckBox inclMasksCheck;
private JCheckBox inclGridsCheck;
private JCheckBox inclFlagsCheck;
protected ProductExpressionPane(boolean booleanExpr,
Product[] products,
Product currentProduct,
PropertyMap preferences) {
super(booleanExpr, null, preferences);
if (products == null || products.length == 0) {
throw new IllegalArgumentException("no products given");
}
this.products = products;
this.currentProduct = currentProduct != null ? currentProduct : this.products[0];
this.targetProduct = this.currentProduct;
init();
}
public static ProductExpressionPane createBooleanExpressionPane(Product[] products,
Product currentProduct,
PropertyMap preferences) {
return new ProductExpressionPane(true, products, currentProduct, preferences);
}
public static ProductExpressionPane createGeneralExpressionPane(Product[] products,
Product currentProduct,
PropertyMap preferences) {
return new ProductExpressionPane(false, products, currentProduct, preferences);
}
public Product getCurrentProduct() {
return currentProduct;
}
protected void init() {
final int defaultIndex = Arrays.asList(products).indexOf(currentProduct);
Namespace namespace = BandArithmetic.createDefaultNamespace(products,
defaultIndex == -1 ? 0 : defaultIndex);
// We may make type checking an option (checkbox) in UI
setParser(new ParserImpl(namespace, false));
final ActionListener resetNodeListAL = e -> {
if (e.getSource() == productBox) {
setCurrentProduct();
}
resetNodeList();
};
inclBandsCheck = new JCheckBox("Show bands");
inclBandsCheck.addActionListener(resetNodeListAL);
if(!isBooleanExpressionPreferred() || currentProduct.getAllFlagNames().length == 0) {
inclBandsCheck.setSelected(true);
} else {
inclBandsCheck.setSelected(false);
}
inclMasksCheck = new JCheckBox("Show masks");
inclMasksCheck.addActionListener(resetNodeListAL);
if (!isBooleanExpressionPreferred()) {
inclMasksCheck.setSelected(true);
}
inclGridsCheck = new JCheckBox("Show tie-point grids");
inclGridsCheck.addActionListener(resetNodeListAL);
inclFlagsCheck = new JCheckBox("Show single flags");
inclFlagsCheck.addActionListener(resetNodeListAL);
if (isBooleanExpressionPreferred()) {
inclFlagsCheck.setSelected(true);
}
nodeList = createPatternList();
JScrollPane scrollableNodeList = new JScrollPane(nodeList);
Box inclNodeBox = Box.createVerticalBox();
inclNodeBox.add(inclBandsCheck);
inclNodeBox.add(inclMasksCheck);
inclNodeBox.add(inclGridsCheck);
inclNodeBox.add(inclFlagsCheck);
JPanel nodeListPane = new JPanel(new BorderLayout());
nodeListPane.add(new JLabel("Data sources: "), BorderLayout.NORTH);
nodeListPane.add(scrollableNodeList, BorderLayout.CENTER);
nodeListPane.add(inclNodeBox, BorderLayout.SOUTH);
JPanel accessoryPane = createDefaultAccessoryPane(nodeListPane);
setLeftAccessory(accessoryPane);
if (products.length > 1) {
List<String> nameList = new ArrayList<>(products.length);
for (Product product : products) {
String productName = product.getDisplayName();
nameList.add(productName);
}
String currentProductName = currentProduct.getDisplayName();
final String[] productNames = new String[nameList.size()];
nameList.toArray(productNames);
productBox = new JComboBox<>(productNames);
productBox.setEditable(false);
productBox.setEnabled(products.length > 1);
productBox.addActionListener(resetNodeListAL);
productBox.setSelectedItem(currentProductName);
JPanel productPane = new JPanel(new BorderLayout());
productPane.add(new JLabel("Product: "), BorderLayout.WEST);
productPane.add(productBox, BorderLayout.CENTER);
setTopAccessory(productPane);
}
resetNodeList();
}
@Override
public void dispose() {
products = null;
currentProduct = null;
productBox = null;
nodeList = null;
inclBandsCheck = null;
inclMasksCheck = null;
inclGridsCheck = null;
inclFlagsCheck = null;
super.dispose();
}
private void resetNodeList() {
setCurrentProduct();
List<String> listEntries = new ArrayList<>(64);
if (currentProduct != null) {
String[] flagNames = currentProduct.getAllFlagNames();
boolean hasBands = currentProduct.getNumBands() > 0;
boolean hasMasks = currentProduct.getMaskGroup().getNodeCount() > 0;
boolean hasGrids = currentProduct.getNumTiePointGrids() > 0;
boolean hasFlags = flagNames.length > 0;
boolean inclBands = inclBandsCheck.isSelected();
boolean inclMasks = inclMasksCheck.isSelected();
boolean inclGrids = inclGridsCheck.isSelected();
boolean inclFlags = inclFlagsCheck.isSelected();
inclBandsCheck.setEnabled(hasBands);
inclMasksCheck.setEnabled(hasMasks);
inclGridsCheck.setEnabled(hasGrids);
inclFlagsCheck.setEnabled(hasFlags);
if (!hasBands && inclBands) {
inclBandsCheck.setSelected(false);
inclBands = false;
}
if (!hasMasks && inclMasks) {
inclMasksCheck.setSelected(false);
inclMasks = false;
}
if (!hasGrids && inclGrids) {
inclGridsCheck.setSelected(false);
inclGrids = false;
}
if (!hasFlags && inclFlags) {
inclFlagsCheck.setSelected(false);
inclFlags = false;
}
nodeList.setEnabled(inclBands || inclMasks || inclGrids || inclFlags);
final String namePrefix = getNodeNamePrefix();
if (inclBands) {
addBandNameRefs(currentProduct, namePrefix, listEntries);
}
if (inclMasks) {
addMaskNameRefs(currentProduct, namePrefix, listEntries);
}
if (inclGrids) {
addGridNameRefs(currentProduct, namePrefix, listEntries);
}
if (inclFlags) {
addFlagNameRefs(namePrefix, flagNames, listEntries);
}
} else {
nodeList.setEnabled(false);
inclBandsCheck.setEnabled(false);
inclMasksCheck.setEnabled(false);
inclGridsCheck.setEnabled(false);
inclFlagsCheck.setEnabled(false);
}
nodeList.setListData(listEntries.toArray(new String[listEntries.size()]));
}
private void setCurrentProduct() {
if (productBox != null) {
int index = productBox.getSelectedIndex();
if (index != -1) {
currentProduct = products[index];
} else {
currentProduct = null;
}
}
}
private String getNodeNamePrefix() {
final String namePrefix;
if (currentProduct != targetProduct) {
namePrefix = BandArithmetic.getProductNodeNamePrefix(currentProduct);
} else {
namePrefix = "";
}
return namePrefix;
}
private static void addBandNameRefs(Product product, String namePrefix, List<String> list) {
for (int j = 0; j < product.getNumBands(); j++) {
Band band = product.getBandAt(j);
list.add(namePrefix + band.getName());
}
}
private static void addMaskNameRefs(Product product, String namePrefix, List<String> list) {
for (int j = 0; j < product.getMaskGroup().getNodeCount(); j++) {
Mask mask = product.getMaskGroup().get(j);
list.add(namePrefix + mask.getName());
}
}
private static void addGridNameRefs(Product product, String namePrefix, List<String> list) {
for (int j = 0; j < product.getNumTiePointGrids(); j++) {
TiePointGrid grid = product.getTiePointGridAt(j);
list.add(namePrefix + grid.getName());
}
}
private static void addFlagNameRefs(String namePrefix, String[] flagNames, List<String> list) {
for (String flagName : flagNames) {
list.add(namePrefix + flagName);
}
}
}