// Copyright 2003
// Association for Universities for Research in Astronomy, Inc.,
// Observatory Control System, Gemini Telescopes Project.
//
// $Id: ElevationPlotPanel.java,v 1.3 2009/03/09 12:12:43 abrighto Exp $
package jsky.plot;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Calendar;
import java.util.Date;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import jsky.coords.SiteDesc;
import jsky.coords.TargetDesc;
import jsky.coords.WorldCoords;
import jsky.util.I18N;
import jsky.util.Preferences;
import jsky.util.PrintableWithDialog;
import jsky.util.SaveableWithDialog;
import jsky.util.Resources;
import jsky.util.gui.BasicWindowMonitor;
import jsky.util.gui.DateChooserDialog;
import jsky.util.gui.DialogUtil;
import jsky.util.gui.SwingUtil;
import jsky.util.gui.GridBagUtil;
/**
* A panel for displaying an elevation plot for given target positions.
*
* @author Allan Brighton
* @version $Revision: 1.3 $
*/
public class ElevationPlotPanel extends JPanel implements ChangeListener {
// Used to access internationalized strings (see i18n/gui*.proprties)
private static final I18N _I18N = I18N.getInstance(ElevationPlotPanel.class);
// Available observatory sites (call setAvailableSites() to change this)
private static SiteDesc[] _availableSites = {
ElevationPlotUtil.MAUNA_KEA, ElevationPlotUtil.CERRO_PANCHON
};
// Available time zone ids
private static String[] _availableTimeZoneIds = {
ElevationPlotModel.UT,
ElevationPlotModel.LST,
ElevationPlotModel.SITE_TIME
};
// Available time zone display names (corresponding to _availableTimeZones above)
private static String[] _availableTimeZoneDisplayNames = {
"UT",
_I18N.getString("SiderealTime"),
_I18N.getString("SiteTime")
};
// Plot Types
private static final String ALTITUDE = _I18N.getString("Altitude");
private static final String PA = _I18N.getString("ParallacticAngle");
// for saving and restoring user preferences
private static final String _altitudePlotVisiblePrefName =
ElevationPanel.class.getName() + ".altitudePlotVisible";
private static final String _paPlotVisiblePrefName =
ElevationPanel.class.getName() + ".paPlotVisible";
// Displays the elevation plot
private ElevationPanel _elevationPanel;
// Displays the observation chart
private ObservationPanel _observationPanel;
// Displays a tabbed pane containing the data tables
private TablePanel _tablePanel;
// Tabbed pane containing the main windows
private JTabbedPane _mainTabbedPane;
// Used to select a date
private DateChooserDialog _dateChooserDialog;
// Provides the model data for the graph and tables
private ElevationPlotModel _model;
// The top level frame of the target list dialog.
private JFrame _targetListFrame;
// The target list dialog panel.
private TargetListPanel _targetListPanel;
// True if this is the main application window
private boolean _isMainWindow = false;
// Array of buttons corresponding to the available sites
private JRadioButton[] _siteButtons;
// Array of buttons corresponding to the available time zones
private JRadioButton[] _timeZoneButtons;
// Panel holding the plot type buttons
private JPanel _plotTypePanel;
// Array of buttons corresponding to the available time zones
private JCheckBox[] _plotTypeButtons;
// Set to true while updating the GUI from the model
private boolean _ignoreEvents = false;
// Action for printing the graph
private AbstractAction _printAction = new AbstractAction(_I18N.getString("print")) {
public void actionPerformed(ActionEvent evt) {
print();
}
};
// Action for saving the graph to a file in PNG format
private AbstractAction _saveAsAction = new AbstractAction(_I18N.getString("saveAs")) {
public void actionPerformed(ActionEvent evt) {
saveAs();
}
};
// Action for closing the graph frame
private AbstractAction _closeAction = new AbstractAction(_I18N.getString("close")) {
public void actionPerformed(ActionEvent evt) {
close();
}
};
// Action for choosing the date
private AbstractAction _dateAction = new AbstractAction(_I18N.getString("date")) {
public void actionPerformed(ActionEvent evt) {
selectDate();
}
};
// Action for choosing the targets
private AbstractAction _targetsAction = new AbstractAction(_I18N.getString("targets")) {
public void actionPerformed(ActionEvent evt) {
selectTargets();
}
};
/**
* Create an elevation plot panel.
*/
public ElevationPlotPanel() {
Preferences.manageSize(this, new Dimension(800, 400), getClass().getName() + ".size");
_elevationPanel = new ElevationPanel();
_observationPanel = new ObservationPanel();
_tablePanel = new TablePanel();
_mainTabbedPane = new JTabbedPane();
_mainTabbedPane.add(_elevationPanel, "Elevation Plot");
_mainTabbedPane.add(_observationPanel, "Observation Chart");
_mainTabbedPane.add(_tablePanel, "Tables");
_mainTabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
updatePlotOptions();
}
});
GridBagUtil layout = new GridBagUtil(this);
layout.add(_mainTabbedPane, 0, 0, 1, 1, 1.0, 1.0,
GridBagConstraints.BOTH,
GridBagConstraints.CENTER,
new Insets(0, 0, 0, 0));
layout.add(_makeButtonPanel(), 0, 1, 1, 1, 1.0, 0.0,
GridBagConstraints.HORIZONTAL,
GridBagConstraints.SOUTH,
new Insets(6, 11, 6, 11));
}
/**
* Return an array of available observatory sites
*/
public static SiteDesc[] getAvailableSites() {
return _availableSites;
}
/**
* Set the array of available observatory sites (should call before first use of this class)
*/
public static void setAvailableSites(SiteDesc[] sites) {
_availableSites = sites;
}
/**
* Set the model containing the graph data and update the display.
*/
public void setModel(ElevationPlotModel model) {
_model = model;
_elevationPanel.setModel(model);
_observationPanel.setModel(model);
_tablePanel.setModel(model);
_update();
_model.removeChangeListener(this);
_model.addChangeListener(this);
}
/**
* Called when the model changes
*/
public void stateChanged(ChangeEvent e) {
_update();
}
// Update the GUI from the model
private void _update() {
try {
_ignoreEvents = true;
String siteName = _model.getSite().getName();
for (int i = 0; i < _availableSites.length; i++) {
if (siteName.equals(_availableSites[i].getName())) {
if (!_siteButtons[i].isSelected()) {
_siteButtons[i].setSelected(true);
}
break;
}
}
String id = _model.getTimeZoneId();
for (int i = 0; i < _availableTimeZoneIds.length; i++) {
if (id.equals(_availableTimeZoneIds[i])) {
if (!_timeZoneButtons[i].isSelected()) {
_timeZoneButtons[i].setSelected(true);
}
break;
}
}
} finally {
_ignoreEvents = false;
}
}
/**
* Return the model containing the graph data.
*/
public ElevationPlotModel getModel() {
return _model;
}
// Create and return a button panel with site and time options.
private JPanel _makeButtonPanel() {
JPanel panel = new JPanel();
GridBagUtil layout = new GridBagUtil(panel);
layout.add(_makeSitePanel(), 0, 0, 1, 1, 1.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 0, 0, 0));
layout.add(_makePlotTypePanel(), 1, 0, 1, 1, 1.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.CENTER,
new Insets(0, 0, 0, 0));
layout.add(_makeTimePanel(), 2, 0, 1, 1, 1.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.EAST,
new Insets(0, 0, 0, 0));
return panel;
}
// Create and return the "Site" button panel.
private JPanel _makeSitePanel() {
JPanel panel = new JPanel();
SiteDesc[] sites = getAvailableSites();
ButtonGroup group = new ButtonGroup();
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JRadioButton rb = (JRadioButton) e.getSource();
if (!_ignoreEvents && rb.isSelected()) {
setSite(rb.getText());
}
}
};
JLabel label = new JLabel("Site:");
GridBagUtil layout = new GridBagUtil(panel);
layout.add(label, 0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 0, 0, 0));
_siteButtons = new JRadioButton[sites.length];
for (int i = 0; i < sites.length; i++) {
_siteButtons[i] = new JRadioButton(sites[i].getName(), i == 0);
layout.add(_siteButtons[i], i + 1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 3, 0, 0));
group.add(_siteButtons[i]);
_siteButtons[i].addItemListener(itemListener);
}
return panel;
}
// Create and return the plot type button panel.
private JPanel _makePlotTypePanel() {
_plotTypePanel = new JPanel();
String[] types = new String[]{ALTITUDE, PA};
boolean[] selected = new boolean[]{
Preferences.get(_altitudePlotVisiblePrefName, true),
Preferences.get(_paPlotVisiblePrefName, false)
};
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
if (!_ignoreEvents) {
setPlotVisible(cb.getText(), cb.isSelected());
}
}
};
JLabel label = new JLabel("Plot:");
GridBagUtil layout = new GridBagUtil(_plotTypePanel);
layout.add(label, 0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 0, 0, 0));
_plotTypeButtons = new JCheckBox[types.length];
for (int i = 0; i < types.length; i++) {
_plotTypeButtons[i] = new JCheckBox(types[i], selected[i]);
layout.add(_plotTypeButtons[i], i + 1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 3, 0, 0));
_plotTypeButtons[i].addItemListener(itemListener);
setPlotVisible(types[i], selected[i]);
}
return _plotTypePanel;
}
// Create and return the "Time" button panel.
private JPanel _makeTimePanel() {
JPanel panel = new JPanel();
_timeZoneButtons = new JRadioButton[_availableTimeZoneDisplayNames.length];
ButtonGroup group = new ButtonGroup();
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JRadioButton rb = (JRadioButton) e.getSource();
if (!_ignoreEvents && rb.isSelected()) {
String s = rb.getText();
for (int i = 0; i < _availableTimeZoneDisplayNames.length; i++) {
if (_availableTimeZoneDisplayNames[i].equals(s)) {
setTimeZone(_availableTimeZoneDisplayNames[i], _availableTimeZoneIds[i]);
break;
}
}
}
}
};
JLabel label = new JLabel("Time:");
GridBagUtil layout = new GridBagUtil(panel);
layout.add(label, 0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 0, 0, 0));
for (int i = 0; i < _availableTimeZoneDisplayNames.length; i++) {
_timeZoneButtons[i] = new JRadioButton(_availableTimeZoneDisplayNames[i], i == 0);
layout.add(_timeZoneButtons[i], i + 1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NONE,
GridBagConstraints.WEST,
new Insets(0, 3, 0, 0));
group.add(_timeZoneButtons[i]);
_timeZoneButtons[i].addItemListener(itemListener);
}
return panel;
}
/**
* Set the time zone to display the X axis values
*/
public void setTimeZone(String timeZoneDisplayName, String timeZoneId) {
_model.setTimeZone(timeZoneDisplayName, timeZoneId);
}
/**
* Set the telescope site by name
*/
public void setSite(String name) {
for (SiteDesc site : _availableSites) {
if (site.getName().equals(name)) {
_model.setSite(site);
break;
}
}
}
/**
* Set the plot type to "Atltitude" or "Parallactic Angle"
*/
public void setPlotVisible(String name, boolean visible) {
if (name.equals(ALTITUDE)) {
_elevationPanel.setAltitudePlotVisible(visible);
Preferences.set(_altitudePlotVisiblePrefName, visible);
} else if (name.equals(PA)) {
_elevationPanel.setPaPlotVisible(visible);
Preferences.set(_paPlotVisiblePrefName, visible);
_elevationPanel.setY2AxisLabel(ElevationPanel.Y2_AXIS_PA);
if (visible) {
_elevationPanel.setY2AxisLabel(ElevationPanel.Y2_AXIS_PA);
} else {
_elevationPanel.setY2AxisLabel(ElevationPanel.Y2_AXIS_AIRMASS);
}
}
}
// Return the dialog used to select a date
private DateChooserDialog getDateChooserDialog(Calendar cal, boolean controlPane) {
if (_dateChooserDialog == null) {
_dateChooserDialog = new DateChooserDialog(SwingUtil.getFrame(this), cal, controlPane);
}
return _dateChooserDialog;
}
/**
* Display a dialog for printing the graph
*/
public void print() {
Component c = _mainTabbedPane.getSelectedComponent();
if (c instanceof PrintableWithDialog) {
try {
((PrintableWithDialog) c).print();
} catch (Exception e) {
DialogUtil.error(e);
}
}
}
/**
* Display a dialog for saving the currently selected component to a file.
* For graphs and charts, the format is PNG. For tables, ?
*/
public void saveAs() {
Component c = _mainTabbedPane.getSelectedComponent();
if (c instanceof SaveableWithDialog) {
try {
((SaveableWithDialog) c).saveAs();
} catch (Exception e) {
DialogUtil.error(e);
}
}
}
/**
* Return true if this is the main application window
*/
public boolean isMainWindow() {
return _isMainWindow;
}
/**
* Set to true if this is the main application window
*/
public void setIsMainWindow(boolean b) {
_isMainWindow = b;
}
/**
* Close this window's frame
*/
public void close() {
if (isMainWindow()) {
System.exit(0);
} else {
JFrame parent = SwingUtil.getFrame(this);
if (parent != null) {
parent.setVisible(false);
}
}
}
/**
* Dispose of the parent frame
*/
public void dispose() {
JFrame parent = SwingUtil.getFrame(this);
if (parent != null) {
parent.dispose();
}
}
/**
* Display a dialog for selecting the date
*/
public void selectDate() {
Calendar cal = Calendar.getInstance(_model.getTimeZone());
cal.setTime(_model.getDate());
DateChooserDialog dialog = getDateChooserDialog(cal, true);
dialog.setVisible(true);
if (!dialog.isCanceled()) {
Date date = dialog.getDate();
_model.setDate(date);
}
}
/**
* Display a dialog for selecting the target objects
*/
public void selectTargets() {
if (_targetListFrame != null) {
SwingUtil.showFrame(_targetListFrame);
} else {
_targetListFrame = new TargetListFrame();
_targetListPanel = ((TargetListFrame) _targetListFrame).getTargetListPanel();
_targetListPanel.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
_elevationPanel.setLegendItems(null); // causes update of legend items
_model.setTargets(_targetListPanel.getTargets());
}
});
}
_targetListPanel.setTargets(_model.getTargets());
}
/**
* Return the Action for printing the graph
*/
public AbstractAction getPrintAction() {
return _printAction;
}
/**
* Return the Action for saving the graph to a file in PNG format
*/
public AbstractAction getSaveAsAction() {
return _saveAsAction;
}
/**
* Return the Action for closing the graph frame
*/
public AbstractAction getCloseAction() {
return _closeAction;
}
/**
* Return the Action for selecting the date
*/
public AbstractAction getDateAction() {
return _dateAction;
}
/**
* Return the Action for selecting the targets
*/
public AbstractAction getTargetsAction() {
return _targetsAction;
}
// Return the elevation plot
public ElevationPanel getElevationPanel() {
return _elevationPanel;
}
// Return the observation chart
public ObservationPanel getObservationPanel() {
return _observationPanel;
}
/**
* Set the visibility of the graph and chart legends
*/
public void setShowLegend(boolean show) {
_elevationPanel.setShowLegend(show);
_observationPanel.setShowLegend(show);
}
/**
* Update the visibility of the plot option buttons based on the current settings.
*/
public void updatePlotOptions() {
if (_plotTypeButtons != null) {
_plotTypePanel.setVisible(_mainTabbedPane.getSelectedComponent() == _elevationPanel);
}
}
/**
* Test main.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("Elevation Plot");
frame.setIconImage(new ImageIcon(Resources.getResource("images/Plot24.gif")).getImage());
ElevationPlotPanel panel = new ElevationPlotPanel();
frame.setJMenuBar(new ElevationPlotMenuBar(panel));
panel.setIsMainWindow(true);
SiteDesc site = ElevationPlotUtil.MAUNA_KEA;
// Calendar cal = Calendar.getInstance(site.getTimeZone());
// cal.set(2009, Calendar.MARCH, 8, 12, 0, 0);
// Date date = cal.getTime();
Date date = new Date();
TargetDesc[] targets = new TargetDesc[]{
new TargetDesc("m101", new WorldCoords("14:03:12.579", "+54:20:52.95"), "Test target 1", "High", "B2"),
new TargetDesc("m51", new WorldCoords("13:29:52.452", "+47:11:39.83"), "Test target 2", "Low", "B2"),
new TargetDesc("ngc1259", new WorldCoords("03:17:17.172", "+41:23:07.22"), "Test target 3", "Medium", "B2"),
};
panel.setModel(new ElevationPlotModel(site, date, targets));
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new BasicWindowMonitor());
}
}