package org.esa.snap.ui.product;
import org.esa.snap.core.datamodel.Band;
import org.esa.snap.core.datamodel.RasterDataNode;
import org.esa.snap.core.datamodel.TiePointGrid;
import org.esa.snap.ui.GridBagUtils;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class DefaultBandChoosingStrategy implements BandChoosingStrategy {
// @todo 3 nf/se - see ProductSubsetDialog for a similar declarations (code smell!)
private static final Font SMALL_PLAIN_FONT = new Font("SansSerif", Font.PLAIN, 10);
private static final Font SMALL_ITALIC_FONT = SMALL_PLAIN_FONT.deriveFont(Font.ITALIC);
private Band[] allBands;
private Band[] selectedBands;
private TiePointGrid[] allTiePointGrids;
private TiePointGrid[] selectedTiePointGrids;
private boolean multipleProducts;
private int numSelected;
private JCheckBox[] checkBoxes;
private JCheckBox selectAllCheckBox;
private JCheckBox selectNoneCheckBox;
public DefaultBandChoosingStrategy(Band[] allBands, Band[] selectedBands, TiePointGrid[] allTiePointGrids,
TiePointGrid[] selectedTiePointGrids, boolean multipleProducts) {
this.allBands = allBands;
this.selectedBands = selectedBands;
this.allTiePointGrids = allTiePointGrids;
this.selectedTiePointGrids = selectedTiePointGrids;
if (this.allBands == null) {
this.allBands = new Band[0];
}
if (this.selectedBands == null) {
this.selectedBands = new Band[0];
}
if (this.allTiePointGrids == null) {
this.allTiePointGrids = new TiePointGrid[0];
}
if (this.selectedTiePointGrids == null) {
this.selectedTiePointGrids = new TiePointGrid[0];
}
BandSorter.sort(allBands);
this.multipleProducts = multipleProducts;
}
@Override
public Band[] getSelectedBands() {
checkSelectedBandsAndGrids();
return selectedBands;
}
@Override
public TiePointGrid[] getSelectedTiePointGrids() {
checkSelectedBandsAndGrids();
return selectedTiePointGrids;
}
@Override
public JPanel createCheckersPane() {
int length = 0;
if (allBands != null) {
length += allBands.length;
}
if (allTiePointGrids != null) {
length += allTiePointGrids.length;
}
checkBoxes = new JCheckBox[length];
final JPanel checkersPane = GridBagUtils.createPanel();
final GridBagConstraints gbc = GridBagUtils.createConstraints("insets.left=4,anchor=NORTHWEST,fill=HORIZONTAL");
final ActionListener checkListener = createActionListener();
addBandCheckers(new StringBuffer(), checkersPane, gbc, checkListener);
addTiePointCheckers(new StringBuffer(), checkersPane, gbc, checkListener);
GridBagUtils.addVerticalFiller(checkersPane, gbc);
return checkersPane;
}
private void addBandCheckers(final StringBuffer description, final JPanel checkersPane,
final GridBagConstraints gbc, final ActionListener checkListener) {
for (int i = 0; i < allBands.length; i++) {
Band band = allBands[i];
boolean checked = false;
for (Band selectedBand : selectedBands) {
if (band == selectedBand) {
checked = true;
numSelected++;
break;
}
}
description.setLength(0);
description.append(band.getDescription() == null ? "" : band.getDescription());
if (band.getSpectralWavelength() > 0.0) {
description.append(" (");
description.append(band.getSpectralWavelength());
description.append(" nm)");
}
final JCheckBox check = new JCheckBox(getRasterDisplayName(band), checked);
check.setFont(SMALL_PLAIN_FONT);
check.addActionListener(checkListener);
final JLabel label = new JLabel(description.toString());
label.setFont(SMALL_ITALIC_FONT);
gbc.gridy++;
GridBagUtils.addToPanel(checkersPane, check, gbc, "weightx=0,gridx=0");
GridBagUtils.addToPanel(checkersPane, label, gbc, "weightx=1,gridx=1");
checkBoxes[i] = check;
}
}
private void addTiePointCheckers(final StringBuffer description, final JPanel checkersPane,
final GridBagConstraints gbc, final ActionListener checkListener) {
for (int i = 0; i < allTiePointGrids.length; i++) {
TiePointGrid grid = allTiePointGrids[i];
boolean checked = false;
for (TiePointGrid selectedGrid : selectedTiePointGrids) {
if (grid == selectedGrid) {
checked = true;
numSelected++;
break;
}
}
description.setLength(0);
description.append(grid.getDescription() == null ? "" : grid.getDescription());
final JCheckBox check = new JCheckBox(getRasterDisplayName(grid), checked);
check.setFont(SMALL_PLAIN_FONT);
check.addActionListener(checkListener);
final JLabel label = new JLabel(description.toString());
label.setFont(SMALL_ITALIC_FONT);
gbc.gridy++;
GridBagUtils.addToPanel(checkersPane, check, gbc, "weightx=0,gridx=0");
GridBagUtils.addToPanel(checkersPane, label, gbc, "weightx=1,gridx=1");
checkBoxes[i + allBands.length] = check;
}
}
private String getRasterDisplayName(RasterDataNode rasterDataNode) {
return multipleProducts ? rasterDataNode.getDisplayName() : rasterDataNode.getName();
}
private ActionListener createActionListener() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JCheckBox check = (JCheckBox) e.getSource();
if (check.isSelected()) {
numSelected++;
} else {
numSelected--;
}
updateCheckBoxStates();
}
};
}
public void updateCheckBoxStates() {
selectAllCheckBox.setSelected(numSelected == checkBoxes.length);
selectAllCheckBox.setEnabled(numSelected < checkBoxes.length);
selectAllCheckBox.updateUI();
selectNoneCheckBox.setSelected(numSelected == 0);
selectNoneCheckBox.setEnabled(numSelected > 0);
selectNoneCheckBox.updateUI();
}
@Override
public void setCheckBoxes(JCheckBox selectAllCheckBox, JCheckBox selectNoneCheckBox) {
this.selectAllCheckBox = selectAllCheckBox;
this.selectNoneCheckBox = selectNoneCheckBox;
updateCheckBoxStates();
}
@Override
public void selectAll() {
select(true);
}
@Override
public void selectNone() {
select(false);
}
@Override
public boolean atLeastOneBandSelected() {
checkSelectedBandsAndGrids();
return selectedBands.length > 0;
}
@Override
public void selectRasterDataNodes(String[] nodeNames) {
for (int i = 0; i < allBands.length; i++) {
Band band = allBands[i];
for (String nodeName : nodeNames) {
if (nodeName.equals(band.getName())) {
checkBoxes[i].setSelected(true);
numSelected++;
break;
}
}
}
for (int i = 0; i < allTiePointGrids.length; i++) {
TiePointGrid grid = allTiePointGrids[i];
for (String nodeName : nodeNames) {
if (nodeName.equals(grid.getName())) {
checkBoxes[allBands.length + i].setSelected(true);
numSelected++;
break;
}
}
}
updateCheckBoxStates();
}
private void checkSelectedBandsAndGrids() {
final List<Band> bands = new ArrayList<>();
final List<TiePointGrid> grids = new ArrayList<>();
for (int i = 0; i < checkBoxes.length; i++) {
JCheckBox checkBox = checkBoxes[i];
if (checkBox.isSelected()) {
if (allBands.length > i) {
bands.add(allBands[i]);
} else {
grids.add(allTiePointGrids[i - allBands.length]);
}
}
}
selectedBands = bands.toArray(new Band[bands.size()]);
selectedTiePointGrids = grids.toArray(new TiePointGrid[grids.size()]);
}
private void select(boolean b) {
for (JCheckBox checkBox : checkBoxes) {
if (b && !checkBox.isSelected()) {
numSelected++;
}
if (!b && checkBox.isSelected()) {
numSelected--;
}
checkBox.setSelected(b);
}
updateCheckBoxStates();
}
}