/*
* 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.rcp.colormanip;
import com.bc.ceres.binding.Property;
import com.bc.ceres.binding.PropertyContainer;
import com.bc.ceres.binding.ValueRange;
import com.bc.ceres.binding.ValueSet;
import com.bc.ceres.swing.binding.BindingContext;
import org.esa.snap.core.datamodel.Band;
import org.esa.snap.core.datamodel.ColorPaletteDef;
import org.esa.snap.core.datamodel.ImageInfo;
import org.esa.snap.core.datamodel.ProductNodeEvent;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.core.datamodel.Stx;
import org.esa.snap.ui.AbstractDialog;
import org.esa.snap.ui.ImageInfoEditorModel;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.beans.PropertyChangeEvent;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Continuous3BandGraphicalForm implements ColorManipulationChildForm {
private final ColorManipulationForm parentForm;
private final ImageInfoEditor2 imageInfoEditor;
private final ImageInfoEditorSupport imageInfoEditorSupport;
private final JPanel contentPanel;
private final ImageInfoEditorModel3B[] models;
private final RasterDataNode[] initialChannelSources;
private final RasterDataNode[] currentChannelSources;
private final List<RasterDataNode> channelSourcesList;
private final MoreOptionsForm moreOptionsForm;
private int channel;
private static final String GAMMA_PROPERTY = "gamma";
double gamma = 1.0;
private static final String CHANNEL_SOURCE_NAME_PROPERTY = "channelSourceName";
String channelSourceName = "";
public Continuous3BandGraphicalForm(final ColorManipulationForm parentForm) {
this.parentForm = parentForm;
imageInfoEditor = new ImageInfoEditor2(parentForm);
imageInfoEditorSupport = new ImageInfoEditorSupport(imageInfoEditor);
moreOptionsForm = new MoreOptionsForm(this, parentForm.getFormModel().canUseHistogramMatching());
models = new ImageInfoEditorModel3B[3];
initialChannelSources = new RasterDataNode[3];
currentChannelSources = new RasterDataNode[3];
channelSourcesList = new ArrayList<>(32);
channel = 0;
final Property channelSourceNameModel = Property.createForField(this, CHANNEL_SOURCE_NAME_PROPERTY, "");
JComboBox channelSourceNameBox = new JComboBox();
channelSourceNameBox.setEditable(false);
final Property gammaModel = Property.createForField(this, GAMMA_PROPERTY, 1.0);
gammaModel.getDescriptor().setValueRange(new ValueRange(1.0 / 10.0, 10.0));
gammaModel.getDescriptor().setDefaultValue(1.0);
JTextField gammaField = new JTextField();
gammaField.setColumns(6);
gammaField.setHorizontalAlignment(JTextField.RIGHT);
moreOptionsForm.getBindingContext().getPropertySet().addProperty(channelSourceNameModel);
moreOptionsForm.getBindingContext().bind(CHANNEL_SOURCE_NAME_PROPERTY, channelSourceNameBox);
moreOptionsForm.getBindingContext().getPropertySet().addProperty(gammaModel);
moreOptionsForm.getBindingContext().bind(GAMMA_PROPERTY, gammaField);
moreOptionsForm.addRow(new JLabel("Source band: "), channelSourceNameBox);
moreOptionsForm.addRow(new JLabel("Gamma non-linearity: "), gammaField);
final PropertyContainer propertyContainer = new PropertyContainer();
propertyContainer.addProperty(Property.createForField(this, "channel", 0));
propertyContainer.getProperty("channel").getDescriptor().setValueSet(new ValueSet(new Integer[]{0, 1, 2}));
final BindingContext bindingContext = new BindingContext(propertyContainer);
JRadioButton rChannelButton = new JRadioButton("Red");
JRadioButton gChannelButton = new JRadioButton("Green");
JRadioButton bChannelButton = new JRadioButton("Blue");
rChannelButton.setName("rChannelButton");
gChannelButton.setName("gChannelButton");
bChannelButton.setName("bChannelButton");
final ButtonGroup channelButtonGroup = new ButtonGroup();
channelButtonGroup.add(rChannelButton);
channelButtonGroup.add(gChannelButton);
channelButtonGroup.add(bChannelButton);
bindingContext.bind("channel", channelButtonGroup);
bindingContext.addPropertyChangeListener("channel", evt -> acknowledgeChannel());
final JPanel channelButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
channelButtonPanel.add(rChannelButton);
channelButtonPanel.add(gChannelButton);
channelButtonPanel.add(bChannelButton);
contentPanel = new JPanel(new BorderLayout(2, 2));
contentPanel.add(channelButtonPanel, BorderLayout.NORTH);
contentPanel.add(imageInfoEditor, BorderLayout.CENTER);
moreOptionsForm.getBindingContext().addPropertyChangeListener(GAMMA_PROPERTY,
evt -> handleGammaChanged());
moreOptionsForm.getBindingContext().addPropertyChangeListener(CHANNEL_SOURCE_NAME_PROPERTY,
this::handleChannelSourceNameChanged);
}
public Component getContentPanel() {
return contentPanel;
}
@Override
public ColorManipulationForm getParentForm() {
return parentForm;
}
@Override
public void handleFormShown(FormModel formModel) {
RasterDataNode[] rasters = formModel.getRasters();
initialChannelSources[0] = rasters[0];
initialChannelSources[1] = rasters[1];
initialChannelSources[2] = rasters[2];
updateFormModel(formModel);
parentForm.revalidateToolViewPaneControl();
}
@Override
public void handleFormHidden(FormModel formModel) {
imageInfoEditor.setModel(null);
channelSourcesList.clear();
Arrays.fill(models, null);
Arrays.fill(initialChannelSources, null);
Arrays.fill(currentChannelSources, null);
}
@Override
public void updateFormModel(FormModel formModel) {
RasterDataNode[] rasters = formModel.getRasters();
currentChannelSources[0] = rasters[0];
currentChannelSources[1] = rasters[1];
currentChannelSources[2] = rasters[2];
final Band[] availableBands = formModel.getProduct().getBands();
channelSourcesList.clear();
appendToChannelSources(currentChannelSources);
appendToChannelSources(initialChannelSources);
appendToChannelSources(availableBands);
for (int i = 0; i < models.length; i++) {
ImageInfoEditorModel3B oldModel = models[i];
models[i] = new ImageInfoEditorModel3B(parentForm.getFormModel().getModifiedImageInfo(), i);
Continuous1BandGraphicalForm.setDisplayProperties(models[i], currentChannelSources[i]);
if (oldModel != null) {
models[i].setHistogramViewGain(oldModel.getHistogramViewGain());
models[i].setMinHistogramViewSample(oldModel.getMinHistogramViewSample());
models[i].setMaxHistogramViewSample(oldModel.getMaxHistogramViewSample());
}
}
final String[] sourceNames = new String[channelSourcesList.size()];
for (int i = 0; i < channelSourcesList.size(); i++) {
sourceNames[i] = channelSourcesList.get(i).getName();
}
moreOptionsForm.getBindingContext().getPropertySet().getProperty(CHANNEL_SOURCE_NAME_PROPERTY).getDescriptor().setValueSet(new ValueSet(sourceNames));
acknowledgeChannel();
}
private void appendToChannelSources(RasterDataNode[] rasterDataNodes) {
for (RasterDataNode channelSource : rasterDataNodes) {
if (!channelSourcesList.contains(channelSource)) {
channelSourcesList.add(channelSource);
}
}
}
@Override
public void resetFormModel(FormModel formModel) {
updateFormModel(formModel);
imageInfoEditor.computeZoomOutToFullHistogramm();
}
@Override
public void handleRasterPropertyChange(ProductNodeEvent event, RasterDataNode raster) {
ImageInfoEditorModel model = imageInfoEditor.getModel();
if (model != null) {
Continuous1BandGraphicalForm.setDisplayProperties(model, raster);
}
if (event.getPropertyName().equals(RasterDataNode.PROPERTY_NAME_STX)) {
acknowledgeChannel();
}
}
@Override
public RasterDataNode[] getRasters() {
return currentChannelSources.clone();
}
@Override
public MoreOptionsForm getMoreOptionsForm() {
return moreOptionsForm;
}
@Override
public AbstractButton[] getToolButtons() {
return new AbstractButton[]{
imageInfoEditorSupport.autoStretch95Button,
imageInfoEditorSupport.autoStretch100Button,
imageInfoEditorSupport.zoomInVButton,
imageInfoEditorSupport.zoomOutVButton,
imageInfoEditorSupport.zoomInHButton,
imageInfoEditorSupport.zoomOutHButton,
imageInfoEditorSupport.showExtraInfoButton,
};
}
private void acknowledgeChannel() {
RasterDataNode channelSource = currentChannelSources[channel];
final ImageInfoEditorModel3B model = models[channel];
Continuous1BandGraphicalForm.setDisplayProperties(model, channelSource);
imageInfoEditor.setModel(model);
moreOptionsForm.getBindingContext().getBinding(CHANNEL_SOURCE_NAME_PROPERTY).setPropertyValue(channelSource.getName());
moreOptionsForm.getBindingContext().getBinding(GAMMA_PROPERTY).setPropertyValue(gamma);
}
private void handleGammaChanged() {
imageInfoEditor.getModel().setGamma(gamma);
parentForm.applyChanges();
}
private void handleChannelSourceNameChanged(PropertyChangeEvent evt) {
RasterDataNode newChannelSource = null;
for (RasterDataNode rasterDataNode : channelSourcesList) {
if (rasterDataNode.getName().equals(channelSourceName)) {
newChannelSource = rasterDataNode;
break;
}
}
if (newChannelSource == null) {
AbstractDialog.showErrorDialog(contentPanel, MessageFormat.format("Unknown band: ''{0}''", channelSourceName), "Error");
return;
}
final RasterDataNode oldChannelSource = currentChannelSources[channel];
if (newChannelSource != oldChannelSource) {
final Stx stx = parentForm.getStx(newChannelSource);
if (stx != null) {
currentChannelSources[channel] = newChannelSource;
final ImageInfo imageInfo = parentForm.getFormModel().getModifiedImageInfo();
imageInfo.getRgbChannelDef().setSourceName(channel, channelSourceName);
final ImageInfo info = newChannelSource.getImageInfo(com.bc.ceres.core.ProgressMonitor.NULL);
final ColorPaletteDef def = info.getColorPaletteDef();
if (def != null) {
imageInfo.getRgbChannelDef().setMinDisplaySample(channel, def.getMinDisplaySample());
imageInfo.getRgbChannelDef().setMaxDisplaySample(channel, def.getMaxDisplaySample());
}
models[channel] = new ImageInfoEditorModel3B(imageInfo, channel);
Continuous1BandGraphicalForm.setDisplayProperties(models[channel], newChannelSource);
acknowledgeChannel();
parentForm.applyChanges();
} else {
final Object value = evt.getOldValue();
moreOptionsForm.getBindingContext().getBinding(CHANNEL_SOURCE_NAME_PROPERTY).setPropertyValue(value == null ? "" : value);
}
}
}
}