/*
* Copyright (C) 2012 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;
import org.esa.snap.core.dataio.ProductSubsetBuilder;
import org.esa.snap.core.dataio.ProductSubsetDef;
import org.esa.snap.core.datamodel.GeoCoding;
import org.esa.snap.core.datamodel.GeoPos;
import org.esa.snap.core.datamodel.PixelPos;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNodeList;
import org.esa.snap.core.datamodel.ProductNodeNameValidator;
import org.esa.snap.core.datamodel.TiePointGeoCoding;
import org.esa.snap.core.datamodel.TiePointGrid;
import org.esa.snap.core.param.ParamChangeEvent;
import org.esa.snap.core.param.ParamChangeListener;
import org.esa.snap.core.param.Parameter;
import org.esa.snap.core.util.Guardian;
import org.esa.snap.core.util.io.FileUtils;
import org.esa.snap.ui.product.ProductSubsetDialog;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.text.JTextComponent;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
//@todo 1 se/** - add (more) class documentation
public class NewProductDialog extends ModalDialog {
private static final String DEFAULT_NUMBER_TEXT = "####";
private static final String DEFAULT_LATLON_TEXT = "##°";
private static final String COPY_ALL_COMMAND = "all";
private static final String COPY_GEOCODING_COMMAND = "geo";
private static final String COPY_SUBSET_COMMAND = "sub";
private static int numNewProducts = 0;
private Parameter paramNewName;
private Parameter paramNewDesc;
private Parameter paramSourceProduct;
private final ProductNodeList sourceProducts;
private final Window parent;
private String prefix;
private Exception exception;
private boolean sourceProductOwner;
private ProductSubsetDef subsetDef;
private Product editProduct; // currently not used, but possibly later for product editing
private Product resultProduct;
private JButton subsetButton;
private JRadioButton copyAllRButton;
private JRadioButton geocodingRButton;
private JRadioButton subsetRButton;
private JLabel labelWidthInfo;
private JLabel labelHeightInfo;
private JLabel labelCenterLatInfo;
private JLabel labelCenterLonInfo;
private int selectedProductIndex;
public NewProductDialog(Window parent,
ProductNodeList<Product> sourceProducts,
final int selectedSourceIndex,
boolean sourceProductOwner) {
this(parent, sourceProducts, selectedSourceIndex, sourceProductOwner, "subset");
}
public NewProductDialog(Window parent,
ProductNodeList<Product> sourceProducts,
final int selectedSourceIndex, boolean sourceProductOwner,
String prefix) {
super(parent, "New Product", ModalDialog.ID_OK_CANCEL, null); /* I18N */
Guardian.assertNotNull("sourceProducts", sourceProducts);
Guardian.assertGreaterThan("sourceProducts.size()", sourceProducts.size(), 0);
this.sourceProducts = sourceProducts;
selectedProductIndex = selectedSourceIndex;
this.parent = parent;
this.prefix = prefix;
this.sourceProductOwner = sourceProductOwner;
}
@Override
public int show() {
createParameter();
createUI();
updateUI();
return super.show();
}
public void setSubsetDef(ProductSubsetDef subsetDef) {
this.subsetDef = subsetDef;
}
// public void setProductToEdit(Product product) {
// _editProduct = product;
// }
public boolean isSourceProductOwner() {
return sourceProductOwner;
}
public Product getSourceProduct() {
String displayName = paramSourceProduct.getValueAsText();
return (Product) sourceProducts.getByDisplayName(displayName);
}
public Product getResultProduct() {
return resultProduct;
}
@Override
protected void onCancel() {
super.onCancel();
resultProduct = null;
}
@Override
protected void onOK() {
super.onOK();
String prodName = paramNewName.getValueAsText();
String prodDesc = paramNewDesc.getValueAsText();
Product sourceProduct = getSourceProduct();
resultProduct = null;
try {
if (geocodingRButton.isSelected()) {
ProductSubsetDef def = new ProductSubsetDef();
def.addNodeName("latitude");
def.addNodeName("longitude");
def.addNodeName(Product.HISTORY_ROOT_NAME);
resultProduct = ProductSubsetBuilder.createProductSubset(sourceProduct, sourceProductOwner, def,
prodName, prodDesc);
// @todo 1 nf/** - check: do we really need the following code or is it done in the ProductSubsetBuilder?
TiePointGrid latGrid = resultProduct.getTiePointGrid("latitude");
TiePointGrid lonGrid = resultProduct.getTiePointGrid("longitude");
if (latGrid != null && lonGrid != null) {
resultProduct.setSceneGeoCoding(
new TiePointGeoCoding(latGrid, lonGrid, sourceProduct.getSceneGeoCoding().getGeoCRS()));
}
} else if (subsetDef != null && subsetRButton.isSelected()) {
resultProduct = ProductSubsetBuilder.createProductSubset(sourceProduct, sourceProductOwner,
subsetDef, prodName, prodDesc);
} else {
resultProduct = ProductSubsetBuilder.createProductSubset(sourceProduct, sourceProductOwner, null,
prodName, prodDesc);
}
} catch (Exception e) {
exception = e;
}
}
public Exception getException() {
return exception;
}
@Override
protected boolean verifyUserInput() {
boolean b = super.verifyUserInput();
String name = paramNewName.getValueAsText();
boolean bName = name != null && name.length() > 0;
boolean subset = true;
if (subsetRButton.isSelected() && subsetDef == null) {
subset = false;
showErrorDialog("Please define a valid spatial or spectral subset."); /*I18N*/
}
return b && bName && subset;
}
private void createParameter() {
numNewProducts++;
String prodName;
String prodDesc;
String[] valueSet;
boolean enableSourceProduct;
if (editProduct == null) {
valueSet = sourceProducts.getDisplayNames();
Product product = (Product) sourceProducts.getAt(selectedProductIndex);
prodName = createNewProductName(valueSet.length > 0 ? product.getName() : "");
prodDesc = "";
enableSourceProduct = true;
} else {
prodName = editProduct.getName();
prodDesc = editProduct.getDescription();
valueSet = new String[]{prodName};
enableSourceProduct = false;
}
paramNewName = new Parameter("productName", prodName);
paramNewName.getProperties().setLabel("Name"); /* I18N */
paramNewName.getProperties().setNullValueAllowed(false);
paramNewName.getProperties().setValidatorClass(ProductNodeNameValidator.class);
paramNewDesc = new Parameter("productDesc", prodDesc);
paramNewDesc.getProperties().setLabel("Description"); /* I18N */
paramNewDesc.getProperties().setNullValueAllowed(false);
paramSourceProduct = new Parameter("sourceProduct", valueSet[selectedProductIndex]);
paramSourceProduct.getProperties().setValueSet(valueSet);
paramSourceProduct.getProperties().setLabel("Derive from Product"); /* I18N */
paramSourceProduct.getProperties().setValueSetBound(true);
paramSourceProduct.setUIEnabled(enableSourceProduct);
paramSourceProduct.addParamChangeListener(new ParamChangeListener() {
public void parameterValueChanged(ParamChangeEvent event) {
subsetDef = null;
updateUI();
setNewProductName();
}
});
}
private void createUI() {
createButtonsAndLabels();
int line = 0;
JPanel dialogPane = GridBagUtils.createPanel();
final GridBagConstraints gbc = GridBagUtils.createDefaultConstraints();
gbc.gridy = ++line;
GridBagUtils.addToPanel(dialogPane, paramNewName.getEditor().getLabelComponent(), gbc,
"fill=BOTH, weightx=0, insets.top=3");
GridBagUtils.addToPanel(dialogPane, paramNewName.getEditor().getComponent(), gbc, "weightx=1, gridwidth=3");
gbc.gridy = ++line;
GridBagUtils.addToPanel(dialogPane, paramNewDesc.getEditor().getLabelComponent(), gbc,
"weightx=0, gridwidth=1");
GridBagUtils.addToPanel(dialogPane, paramNewDesc.getEditor().getComponent(), gbc, "weightx=1, gridwidth=3");
gbc.gridy = ++line;
GridBagUtils.addToPanel(dialogPane, paramSourceProduct.getEditor().getLabelComponent(), gbc,
"fill=NONE, gridwidth=4, insets.top=15");
gbc.gridy = ++line;
GridBagUtils.addToPanel(dialogPane, paramSourceProduct.getEditor().getComponent(), gbc,
"fill=HORIZONTAL, insets.top=3");
gbc.gridy = ++line;
final JPanel radioPanel = new JPanel(new BorderLayout());
radioPanel.add(copyAllRButton, BorderLayout.WEST);
radioPanel.add(geocodingRButton);
GridBagUtils.addToPanel(dialogPane, radioPanel, gbc, "fill=NONE, gridwidth=2");
GridBagUtils.addToPanel(dialogPane, subsetRButton, gbc, "gridwidth=1, weightx=300, anchor=EAST");
GridBagUtils.addToPanel(dialogPane, subsetButton, gbc, "fill=NONE, weightx=1, anchor=EAST");
gbc.gridy = ++line;
GridBagUtils.addToPanel(dialogPane, createInfoPanel(), gbc,
"fill=BOTH, anchor=WEST, insets.top=10, gridwidth=4");
setContent(dialogPane);
final JComponent editorComponent = paramNewName.getEditor().getEditorComponent();
if (editorComponent instanceof JTextComponent) {
JTextComponent tf = (JTextComponent) editorComponent;
tf.selectAll();
tf.requestFocus();
}
}
private JPanel createInfoPanel() {
final JPanel infoPanel = GridBagUtils.createDefaultEmptyBorderPanel();
infoPanel.setBorder(UIUtils.createGroupBorder("Output Product Information"));
final GridBagConstraints gbc2 = GridBagUtils.createDefaultConstraints();
GridBagUtils.addToPanel(infoPanel, new JLabel("Scene Width:"), gbc2);
GridBagUtils.addToPanel(infoPanel, labelWidthInfo, gbc2);
GridBagUtils.addToPanel(infoPanel, new JLabel("pixel"), gbc2, "weightx=1");
GridBagUtils.addToPanel(infoPanel, new JLabel("Scene Height:"), gbc2, "gridy=1, weightx=0");
GridBagUtils.addToPanel(infoPanel, labelHeightInfo, gbc2);
GridBagUtils.addToPanel(infoPanel, new JLabel("pixel"), gbc2, "weightx=1");
GridBagUtils.addToPanel(infoPanel, new JLabel("Center Latitude:"), gbc2, "gridy=2, weightx=0");
GridBagUtils.addToPanel(infoPanel, labelCenterLatInfo, gbc2, "weightx=1, gridwidth=2");
GridBagUtils.addToPanel(infoPanel, new JLabel("Center Longitude:"), gbc2, "gridy=3, weightx=0, gridwidth=1");
GridBagUtils.addToPanel(infoPanel, labelCenterLonInfo, gbc2, "weightx=1, gridwidth=2");
return infoPanel;
}
private void createButtonsAndLabels() {
copyAllRButton = new JRadioButton("Copy");
geocodingRButton = new JRadioButton("Use Geocoding Only");
subsetRButton = new JRadioButton("Use Subset");
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(copyAllRButton);
buttonGroup.add(geocodingRButton);
buttonGroup.add(subsetRButton);
copyAllRButton.setActionCommand(COPY_ALL_COMMAND);
geocodingRButton.setActionCommand(COPY_GEOCODING_COMMAND);
subsetRButton.setActionCommand(COPY_SUBSET_COMMAND);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateUI();
}
};
copyAllRButton.addActionListener(listener);
geocodingRButton.addActionListener(listener);
subsetRButton.addActionListener(listener);
if (subsetDef != null) {
subsetRButton.setSelected(true);
} else {
geocodingRButton.setSelected(true);
}
subsetButton = new JButton("Subset...");
subsetButton.addActionListener(createSubsetButtonListener());
labelWidthInfo = new JLabel(DEFAULT_NUMBER_TEXT);
labelHeightInfo = new JLabel(DEFAULT_NUMBER_TEXT);
labelCenterLatInfo = new JLabel(DEFAULT_LATLON_TEXT);
labelCenterLonInfo = new JLabel(DEFAULT_LATLON_TEXT);
}
private void updateUI() {
Product product = getSourceProduct();
if (subsetDef == null) {
subsetButton.setText("Define subset ...");
if (product != null) {
final int width = product.getSceneRasterWidth();
final int height = product.getSceneRasterHeight();
labelWidthInfo.setText("" + width);
labelHeightInfo.setText("" + height);
final GeoCoding geoCoding = product.getSceneGeoCoding();
if (geoCoding != null) {
final GeoPos pos = geoCoding.getGeoPos(new PixelPos(0.5f * width + 0.5f, 0.5f * height + 0.5f),
null);
labelCenterLatInfo.setText(pos.getLatString());
labelCenterLonInfo.setText(pos.getLonString());
} else {
labelCenterLatInfo.setText(DEFAULT_LATLON_TEXT);
labelCenterLonInfo.setText(DEFAULT_LATLON_TEXT);
}
} else {
labelWidthInfo.setText(DEFAULT_NUMBER_TEXT);
labelHeightInfo.setText(DEFAULT_NUMBER_TEXT);
labelCenterLatInfo.setText(DEFAULT_LATLON_TEXT);
labelCenterLonInfo.setText(DEFAULT_LATLON_TEXT);
}
} else {
subsetButton.setText("Edit Subset...");
final Rectangle region = subsetDef.getRegion();
final int subSamplingX = subsetDef.getSubSamplingX();
final int subSamplingY = subsetDef.getSubSamplingY();
labelWidthInfo.setText("" + ((region.width - 1) / subSamplingX + 1));
labelHeightInfo.setText("" + ((region.height - 1) / subSamplingY + 1));
if (product == null) {
labelCenterLatInfo.setText(DEFAULT_LATLON_TEXT);
labelCenterLonInfo.setText(DEFAULT_LATLON_TEXT);
} else {
final GeoCoding geoCoding = product.getSceneGeoCoding();
if (geoCoding == null) {
labelCenterLatInfo.setText(DEFAULT_LATLON_TEXT);
labelCenterLonInfo.setText(DEFAULT_LATLON_TEXT);
} else {
final float centerX = 0.5f * region.width + region.x;
final float centerY = 0.5f * region.height + region.y;
final PixelPos centerPoint = new PixelPos(centerX + 0.5f, centerY + 0.5f);
final GeoPos pos = geoCoding.getGeoPos(centerPoint, null);
labelCenterLatInfo.setText(pos.getLatString());
labelCenterLonInfo.setText(pos.getLonString());
}
}
}
final boolean geocodingAvailable = product != null && product.getSceneGeoCoding() != null;
geocodingRButton.setEnabled(geocodingAvailable);
if (geocodingRButton.isSelected() && !geocodingAvailable) {
subsetRButton.setSelected(true);
}
subsetButton.setEnabled(subsetRButton.isSelected());
}
private ActionListener createSubsetButtonListener() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
Product product = getSourceProduct();
if (product == null) {
return;
}
ProductSubsetDialog dialog = new ProductSubsetDialog(parent, product, subsetDef);
if (dialog.show() == ProductSubsetDialog.ID_OK) {
if (dialog.getProductSubsetDef().isEntireProductSelected()) {
subsetDef = null;
} else {
subsetDef = dialog.getProductSubsetDef();
}
}
updateUI();
}
};
}
private boolean hasPrefix() {
return prefix != null && prefix.length() > 1;
}
private void setNewProductName() {
final String newProductName = createNewProductName(getSourceProduct().getName());
paramNewName.setValue(newProductName, null);
}
private String createNewProductName(String sourceProductName) {
String newNameBase = "";
if (sourceProductName != null && sourceProductName.length() > 0) {
newNameBase = FileUtils.exchangeExtension(sourceProductName, "");
}
String newNamePrefix = "product";
if (hasPrefix()) {
newNamePrefix = prefix;
}
String newProductName;
if (newNameBase.length() > 0) {
newProductName = newNamePrefix + "_" + numNewProducts + "_" + newNameBase;
} else {
newProductName = newNamePrefix + "_" + numNewProducts;
}
return newProductName;
}
}