package edu.colostate.vchill.gui;
import edu.colostate.vchill.Config;
import edu.colostate.vchill.Config.GradientType;
import edu.colostate.vchill.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.util.Observable;
import java.util.Observer;
/**
* The ViewFilterPanel allows access to various options for
* plot windows without constantly right-clicking.
*
* @author Jochen Deyke
* @author jpont
* @version 2009-03-19
*/
public class ViewFilterPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = -1728050194660302405L;
private final static ViewFilterPanel me = new ViewFilterPanel();
private final ViewActions actions = new ViewActions();
private final Config config = Config.getInstance();
private final ViewControl vc = ViewControl.getInstance();
private final ScaleManager sm = ScaleManager.getInstance();
private final WindowManager wm = WindowManager.getInstance();
private final JTextField thresholdField = new JTextField(String.valueOf(config.getThresholdFilterCutoff()), 4);
private final JComboBox threshBox = new JComboBox(sm.getTypes().toArray());
private final JCheckBox enableThreshCheckBox = new JCheckBox(new AbstractAction("Threshold:") {
/**
*
*/
private static final long serialVersionUID = -2602346584637503100L;
public void actionPerformed(final ActionEvent ae) {
config.setThresholdEnabled(enableThreshCheckBox.isSelected());
vc.rePlot();
}
});
private final JCheckBox absoluteValueCheckBox = new JCheckBox(new AbstractAction("Absolute") {
/**
*
*/
private static final long serialVersionUID = -930118262416813946L;
public void actionPerformed(final ActionEvent ae) {
config.setThresholdAbsoluteValueEnabled(absoluteValueCheckBox.isSelected());
vc.rePlot();
}
});
private final JCheckBox enableThreshGreaterThanCheckBox = new JCheckBox(new AbstractAction(">") {
/**
*
*/
private static final long serialVersionUID = 596592460487632904L;
public void actionPerformed(final ActionEvent ae) {
config.setThresholdGreaterThanEnabled(enableThreshGreaterThanCheckBox.isSelected());
vc.rePlot();
}
});
private final JCheckBox enableSmoothingCheckBox = new JCheckBox("Smoothing");
private final JCheckBox enableNoiseFilterCheckBox = new JCheckBox("Noise Reduction");
private final JRadioButton unfoldingOff = new JRadioButton(new AbstractAction("Off") {
/**
*
*/
private static final long serialVersionUID = -1717451052853371776L;
public void actionPerformed(final ActionEvent ae) {
System.out.println("Disable Velocity Unfolding");
config.setUnfoldingEnabled(false);
vc.rePlot();
}
});
private final JRadioButton unfoldingAutomatic = new JRadioButton(new AbstractAction("Automatic") {
/**
*
*/
private static final long serialVersionUID = 6980738617850652817L;
public void actionPerformed(final ActionEvent ae) {
System.out.println("Automatic Velocity Unfolding");
config.setUnfoldingEnabled(true);
config.setUnfoldingAutomatic(true);
vc.rePlot();
}
});
private final JRadioButton unfoldingManual = new JRadioButton(new AbstractAction("Manual") {
/**
*
*/
private static final long serialVersionUID = 8532588443991534687L;
public void actionPerformed(final ActionEvent ae) {
System.out.println("Manual Velocity Unfolding");
config.setUnfoldingEnabled(true);
config.setUnfoldingAutomatic(false);
vc.rePlot();
}
});
private final JTextField unfoldingStartRange = new JTextField(String.valueOf(config.getUnfoldStartRange()), 4);
private final JRadioButton gradientOff = new JRadioButton(new AbstractAction("Off") {
/**
*
*/
private static final long serialVersionUID = 7378725759773571609L;
public void actionPerformed(final ActionEvent ae) {
System.out.println("Gradient Off");
config.setGradientType(GradientType.Off);
vc.rePlot();
}
});
private final JRadioButton gradientRange = new JRadioButton(new AbstractAction("Range") {
/**
*
*/
private static final long serialVersionUID = 6959511413938691924L;
public void actionPerformed(ActionEvent ae) {
System.out.println("Z Range Gradient");
config.setGradientType(GradientType.Range);
vc.rePlot();
}
});
private final JRadioButton gradientAzimuth = new JRadioButton(new AbstractAction("Azimuth") {
/**
*
*/
private static final long serialVersionUID = -555090219952498927L;
public void actionPerformed(ActionEvent ae) {
System.out.println("Z Azimuth Gradient");
config.setGradientType(GradientType.Azimuth);
vc.rePlot();
}
});
private final AbstractAction threshBoxAction = new AbstractAction() {
/**
*
*/
private static final long serialVersionUID = 4231079353073560442L;
public void actionPerformed(final ActionEvent ae) {
String type = (String) threshBox.getSelectedItem();
if (type == null) return;
System.out.println("Setting thresh type to " + type);
config.setThresholdType(type);
ViewRemotePanel.getInstance().update();
vc.rePlot();
}
};
/**
* This basic constructor will call the helper methods and setup the
* size and layout of the inner components. Private default constructor
* prevents instantiation.
*/
private ViewFilterPanel() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(createThresholdOptions());
add(createThresholdBox());
add(new JSeparator()); //--------------------------------
add(createSmoothingOptions());
add(new JSeparator()); //--------------------------------
add(createUnfoldingOptions());
add(createUnfoldingBox());
add(createUnfoldingButton());
add(new JSeparator()); //--------------------------------
add(createGradientOptions());
sm.addObserver(new Observer() {
public void update(final Observable o, final Object arg) {
threshBox.setAction(null);
threshBox.removeAllItems();
for (String type : sm.getTypes()) threshBox.addItem(type);
String thresh = config.getThresholdType();
threshBox.setSelectedItem(thresh);
threshBox.setAction(threshBoxAction);
}
});
update();
}
public static ViewFilterPanel getInstance() {
return me;
}
private void setThresholdCutoff(final String cutoff) {
if (cutoff == null || cutoff.length() < 1) return;
config.setThresholdFilterCutoff(Double.parseDouble(cutoff));
}
private JPanel createThresholdOptions() {
JPanel inputPanel = new JPanel();
MyAction action = new MyAction() {
protected void update() {
setThresholdCutoff(thresholdField.getText());
}
};
enableThreshCheckBox.setToolTipText("Remove below given cutoff value");
inputPanel.add(enableThreshCheckBox);
enableThreshGreaterThanCheckBox.setToolTipText("Remove data above instead of below cutoff value");
inputPanel.add(enableThreshGreaterThanCheckBox);
thresholdField.addActionListener(action);
thresholdField.addFocusListener(action);
thresholdField.setToolTipText("Cutoff value for threshold filter");
inputPanel.add(thresholdField);
absoluteValueCheckBox.setToolTipText("Take absolute value of data before checking threshold");
inputPanel.add(absoluteValueCheckBox);
return inputPanel;
}
private JPanel createThresholdBox() {
JPanel inputPanel = new JPanel();
inputPanel.add(threshBox);
return inputPanel;
}
private JPanel createSmoothingOptions() {
JPanel inputPanel = new JPanel();
enableSmoothingCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
config.setSmoothingEnabled(enableSmoothingCheckBox.isSelected());
vc.rePlot();
}
});
enableSmoothingCheckBox.setToolTipText("Smooth image by averaging data in a 3x3 grid");
inputPanel.add(enableSmoothingCheckBox);
inputPanel.add(new JPanel());
enableNoiseFilterCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
config.setNoiseReductionEnabled(enableNoiseFilterCheckBox.isSelected());
vc.rePlot();
}
});
enableNoiseFilterCheckBox.setToolTipText("Clean image by removing isolated data points");
inputPanel.add(enableNoiseFilterCheckBox);
return inputPanel;
}
private JPanel createUnfoldingOptions() {
JPanel inputPanel = new JPanel();
inputPanel.add(new JLabel("Unfolding: "));
ButtonGroup group = new ButtonGroup();
group.add(unfoldingOff);
group.add(unfoldingAutomatic);
group.add(unfoldingManual);
unfoldingOff.setToolTipText("No unfolding will be done");
unfoldingAutomatic.setToolTipText("Unfold supported fields on a best-guess basis");
unfoldingManual.setToolTipText("Unfold supported fields based on user-entered numbers");
inputPanel.add(unfoldingOff);
inputPanel.add(unfoldingAutomatic);
inputPanel.add(unfoldingManual);
return inputPanel;
}
private JPanel createUnfoldingBox() {
JPanel inputPanel = new JPanel();
inputPanel.add(new JLabel("Unfolding start range (km): "));
unfoldingStartRange.setToolTipText("The range (km) where the unfolding algorithm will start");
MyAction action = new MyAction() {
protected void update() {
String rangeText = unfoldingStartRange.getText();
if (rangeText != null && rangeText.length() >= 1) {
double range = Double.parseDouble(rangeText);
if (range >= 0.0) {
config.setUnfoldStartRange(range);
if (config.isUnfoldingEnabled())
vc.rePlot();
}
}
}
};
unfoldingStartRange.addActionListener(action);
inputPanel.add(unfoldingStartRange);
return inputPanel;
}
private JPanel createUnfoldingButton() {
JPanel inputPanel = new JPanel();
inputPanel.add(new JButton(new AbstractAction("Input New Velocity Estimates") {
/**
*
*/
private static final long serialVersionUID = -3563303124266525281L;
public void actionPerformed(final ActionEvent ae) {
System.out.println("Input Manual Unfolding Estimates");
String result = DialogUtil.showMultilineInputDialog("Input", "Please enter estimated velocities, one per line.\nFormat is <height in km><space><estimated velocity in m/s>\nEntered values remain in effect until the program is shut down or new numbers are entered.\nOrdering of heights is not important. Faulty lines are ignored.", EstimateParser.getInstance().toString());
if (result == null) return; //canceled;
EstimateParser.getInstance().parse(result);
config.setUnfoldingEnabled(true);
config.setUnfoldingAutomatic(false);
update();
vc.rePlot();
}
}));
return inputPanel;
}
private JPanel createGradientOptions() {
JPanel inputPanel = new JPanel();
inputPanel.add(new JLabel("Gradient: "));
ButtonGroup group = new ButtonGroup();
group.add(gradientOff);
group.add(gradientRange);
group.add(gradientAzimuth);
gradientOff.setToolTipText("Normal view of data");
gradientRange.setToolTipText("For supported fields, display the difference between the current point and the next in range instead of raw data");
gradientAzimuth.setToolTipText("For supported fields, display the difference between the current point and the next in azimuth instead of raw data");
inputPanel.add(gradientOff);
inputPanel.add(gradientRange);
inputPanel.add(gradientAzimuth);
return inputPanel;
}
/**
* Reloads text fields based on current settings in Config
*/
public void update() {
enableThreshCheckBox.setSelected(config.isThresholdEnabled());
absoluteValueCheckBox.setSelected(config.isThresholdAbsoluteValue());
enableThreshGreaterThanCheckBox.setSelected(config.isThresholdGreaterThan());
threshBox.setAction(null);
threshBox.setSelectedItem(config.getThresholdType());
threshBox.setAction(threshBoxAction);
enableSmoothingCheckBox.setSelected(config.isSmoothingEnabled());
enableNoiseFilterCheckBox.setSelected(config.isNoiseReductionEnabled());
if (config.isUnfoldingEnabled()) {
if (config.isUnfoldingAutomatic()) unfoldingAutomatic.setSelected(true);
else unfoldingManual.setSelected(true);
} else unfoldingOff.setSelected(true);
switch (config.getGradientType()) {
case Range:
gradientRange.setSelected(true);
break;
case Azimuth:
gradientAzimuth.setSelected(true);
break;
default:
gradientOff.setSelected(true);
break;
}
}
private abstract class MyAction implements ActionListener, FocusListener {
public void actionPerformed(final ActionEvent ae) {
update();
vc.rePlot();
}
public void focusLost(final FocusEvent fe) {
update();
}
public void focusGained(final FocusEvent fe) {
} //do nothing
protected abstract void update();
}
}