/*
* 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.rcp.statistics;
import com.bc.ceres.binding.Property;
import com.bc.ceres.binding.ValueSet;
import com.bc.ceres.core.Assert;
import com.bc.ceres.swing.binding.BindingContext;
import com.bc.ceres.swing.binding.Enablement;
import org.esa.snap.core.datamodel.Mask;
import org.esa.snap.core.datamodel.Product;
import org.esa.snap.core.datamodel.ProductNode;
import org.esa.snap.core.datamodel.ProductNodeEvent;
import org.esa.snap.core.datamodel.ProductNodeGroup;
import org.esa.snap.core.datamodel.ProductNodeListener;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.ui.GridBagUtils;
import org.esa.snap.ui.tool.ToolButtonFactory;
import org.openide.util.ImageUtilities;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import javax.swing.AbstractButton;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.util.ArrayList;
import java.util.List;
class RoiMaskSelector {
public final static String PROPERTY_NAME_USE_ROI_MASK = "useRoiMask";
public final static String PROPERTY_NAME_ROI_MASK = "roiMask";
final JCheckBox useRoiMaskCheckBox;
final JComboBox roiMaskComboBox;
final AbstractButton showMaskManagerButton;
private final BindingContext bindingContext;
private final ProductNodeListener productNodeListener;
private Product product;
private RasterDataNode raster;
private Enablement useRoiEnablement;
private Enablement roiMaskEnablement;
private AbstractButton createShowMaskManagerButton() {
final AbstractButton showMaskManagerButton =
ToolButtonFactory.createButton(ImageUtilities.loadImageIcon("org/esa/snap/rcp/icons/MaskManager24.png", false), false);
showMaskManagerButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
final TopComponent maskManagerTopComponent = WindowManager.getDefault().findTopComponent("MaskManagerTopComponent");
maskManagerTopComponent.open();
maskManagerTopComponent.requestActive();
}));
return showMaskManagerButton;
}
public RoiMaskSelector(BindingContext bindingContext) {
final Property useRoiMaskProperty = bindingContext.getPropertySet().getProperty(PROPERTY_NAME_USE_ROI_MASK);
Assert.argument(useRoiMaskProperty != null, "bindingContext");
Assert.argument(useRoiMaskProperty.getType().equals(Boolean.class) || useRoiMaskProperty.getType() == Boolean.TYPE, "bindingContext");
Assert.argument(bindingContext.getPropertySet().getProperty(PROPERTY_NAME_ROI_MASK) != null, "bindingContext");
Assert.argument(bindingContext.getPropertySet().getProperty(PROPERTY_NAME_ROI_MASK).getType().equals(Mask.class), "bindingContext");
this.productNodeListener = new PNL();
this.bindingContext = bindingContext;
useRoiMaskCheckBox = new JCheckBox("Use ROI mask:");
roiMaskComboBox = new JComboBox();
roiMaskComboBox.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value != null) {
this.setText(((Mask) value).getName());
}
return this;
}
});
this.showMaskManagerButton = createShowMaskManagerButton();
bindingContext.bind(PROPERTY_NAME_USE_ROI_MASK, useRoiMaskCheckBox);
bindingContext.bind(PROPERTY_NAME_ROI_MASK, roiMaskComboBox);
bindingContext.bindEnabledState(PROPERTY_NAME_USE_ROI_MASK, true, createUseRoiCondition());
bindingContext.bindEnabledState(PROPERTY_NAME_ROI_MASK, true, createEnableMaskDropDownCondition());
}
public JPanel createPanel() {
final JPanel roiMaskPanel = GridBagUtils.createPanel();
GridBagConstraints roiMaskPanelConstraints = GridBagUtils.createConstraints("anchor=SOUTHWEST,fill=HORIZONTAL,insets.top=2");
GridBagUtils.addToPanel(roiMaskPanel, useRoiMaskCheckBox, roiMaskPanelConstraints,
",gridy=0,gridx=0,weightx=1");
GridBagUtils.addToPanel(roiMaskPanel, roiMaskComboBox, roiMaskPanelConstraints,
"gridy=1,insets.left=4");
GridBagUtils.addToPanel(roiMaskPanel, showMaskManagerButton, roiMaskPanelConstraints,
"gridheight=2,gridy=0,gridx=1,weightx=0,ipadx=5,insets.left=0");
return roiMaskPanel;
}
public void updateMaskSource(Product newProduct, RasterDataNode newRaster) {
if (product != newProduct) {
if (product != null) {
product.removeProductNodeListener(productNodeListener);
}
if (newProduct != null) {
newProduct.addProductNodeListener(productNodeListener);
}
this.product = newProduct;
}
if (raster != newRaster) {
this.raster = newRaster;
}
updateRoiMasks();
}
private void updateRoiMasks() {
final Property property = bindingContext.getPropertySet().getProperty(PROPERTY_NAME_ROI_MASK);
if (product != null && raster != null) {
//todo [multisize_products] compare scenerastertransform (or its successor) rather than size
final ProductNodeGroup<Mask> maskGroup = product.getMaskGroup();
List<ProductNode> maskList = new ArrayList<>();
final Dimension refRrasterSize = raster.getRasterSize();
for (int i = 0; i < maskGroup.getNodeCount(); i++) {
final Mask mask = maskGroup.get(i);
if (refRrasterSize.equals(mask.getRasterSize())) {
maskList.add(mask);
}
}
property.getDescriptor().setValueSet(new ValueSet(maskList.toArray(new ProductNode[maskList.size()])));
} else {
property.getDescriptor().setValueSet(new ValueSet(new Mask[0]));
}
useRoiEnablement.apply();
roiMaskEnablement.apply();
}
private Enablement.Condition createUseRoiCondition() {
return new Enablement.Condition() {
@Override
public boolean evaluate(BindingContext bindingContext) {
return product != null && product.getMaskGroup().getNodeCount() > 0;
}
@Override
public void install(BindingContext bindingContext, Enablement enablement) {
useRoiEnablement = enablement;
}
@Override
public void uninstall(BindingContext bindingContext, Enablement enablement) {
useRoiEnablement = null;
}
};
}
private Enablement.Condition createEnableMaskDropDownCondition() {
return new Enablement.Condition() {
@Override
public boolean evaluate(BindingContext bindingContext) {
Boolean propertyValue = bindingContext.getPropertySet().getValue(PROPERTY_NAME_USE_ROI_MASK);
if (roiMaskComboBox.getItemCount() > 0 && roiMaskComboBox.getSelectedIndex() < 0) {
roiMaskComboBox.setSelectedIndex(0);
}
return Boolean.TRUE.equals(propertyValue)
&& product != null
&& product.getMaskGroup().getNodeCount() > 0;
}
@Override
public void install(BindingContext bindingContext, Enablement enablement) {
bindingContext.addPropertyChangeListener(PROPERTY_NAME_USE_ROI_MASK, enablement);
roiMaskEnablement = enablement;
}
@Override
public void uninstall(BindingContext bindingContext, Enablement enablement) {
bindingContext.removePropertyChangeListener(PROPERTY_NAME_USE_ROI_MASK, enablement);
roiMaskEnablement = null;
}
};
}
private class PNL implements ProductNodeListener {
@Override
public void nodeAdded(ProductNodeEvent event) {
handleEvent(event);
}
@Override
public void nodeChanged(ProductNodeEvent event) {
handleEvent(event);
}
@Override
public void nodeDataChanged(ProductNodeEvent event) {
handleEvent(event);
}
@Override
public void nodeRemoved(ProductNodeEvent event) {
handleEvent(event);
}
private void handleEvent(ProductNodeEvent event) {
ProductNode sourceNode = event.getSourceNode();
if (sourceNode instanceof Mask) {
updateRoiMasks();
}
}
}
}