package com.isti.xmax.gui;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.border.EtchedBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JScrollPane;
import com.isti.xmax.XMAX;
import com.isti.xmax.common.Earthquake;
import com.isti.traceview.common.IEvent;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JSplitPane;
import javax.swing.BoxLayout;
import org.apache.log4j.Logger;
/**
* Side-panel for earthquakes and phases selection. Contain list if available earthquakes (i.e those
* from list from XMAXDataModule which may have arrivals in the current time range) and list of phase
* names. First user selects earthquakes, then phases list updates for current earthquakes
* selection, and he selects phases from updated list. Selected earthquakes and phases shows as a
* marks on graph panel.
*
* @author Max Kokoulin
*/
public class PhasePanel extends JPanel implements ListSelectionListener {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(PhasePanel.class); // @jve:decl-index=0:
private static SimpleDateFormat df = new SimpleDateFormat("yyyy,DDD,HH:mm:ss");
private static Object[] initialSelectedPhases = { "P" };
static {
df.setTimeZone(XMAX.timeZone);
}
private JScrollPane earthquakesSP = null;
private JScrollPane phasesSP = null;
private PhaseList earthquakesL = null;
private PhaseList phasesL = null;
private JSplitPane splitter = null;
private XMAXGraphPanel graphPanel = null;
private boolean init = false;
/**
* Earthquakes ever selected to fill selection
*/
private Set<IEvent> everSelectedEarthquakes = null; // @jve:decl-index=0:
/**
* Phases ever selected to fill selection
*/
private Set<String> everSelectedPhases = null; // @jve:decl-index=0:
/**
* This method initializes phase panel
*/
public PhasePanel(XMAXGraphPanel gp) {
super();
this.graphPanel = gp;
initialize();
init = true;
refreshAvailableEarthQuakes();
splitter.setDividerLocation(new Double(gp.getHeight() / 3).intValue());
init = false;
earthquakesL.setSelectedValues(graphPanel.getAvailableEarthquakes(), false);
phasesL.setSelectedValues(initialSelectedPhases, false);
}
/**
* This method initializes this phase panel
*/
private void initialize() {
this.setPreferredSize(new Dimension(120, 100));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(getSplitter(), null);
everSelectedEarthquakes = new HashSet<IEvent>();
everSelectedPhases = new HashSet<String>();
}
/**
* This method initializes earthquakesSP
*
* @return javax.swing.JScrollPane
*/
private JScrollPane getEarthquakesSP() {
if (earthquakesSP == null) {
earthquakesSP = new JScrollPane();
earthquakesSP.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
earthquakesSP.setViewportView(getEarthquakesL());
earthquakesSP.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
}
return earthquakesSP;
}
/**
* This method initializes phasesSP
*
* @return javax.swing.JScrollPane
*/
private JScrollPane getPhasesSP() {
if (phasesSP == null) {
phasesSP = new JScrollPane();
phasesSP.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
phasesSP.setViewportView(getPhasesL());
phasesSP.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
}
return phasesSP;
}
/**
* This method initializes earthquakesL
*
* @return javax.swing.JList
*/
private JList<?> getEarthquakesL() {
if (earthquakesL == null) {
earthquakesL = new PhaseList(XMAX.getDataModule().getEarthquakes().toArray());
earthquakesL.setCellRenderer(new EarthquakeCellRenderer());
earthquakesL.addListSelectionListener(this);
}
return earthquakesL;
}
/**
* This method initializes phasesL
*
* @return javax.swing.JList
*/
private JList<?> getPhasesL() {
if (phasesL == null) {
phasesL = new PhaseList();
phasesL.addListSelectionListener(this);
}
return phasesL;
}
/**
* This method initializes splitter
*
* @return javax.swing.JSplitPane
*/
private JSplitPane getSplitter() {
if (splitter == null) {
splitter = new JSplitPane();
splitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
splitter.setDividerSize(3);
splitter.setBottomComponent(getPhasesSP());
splitter.setTopComponent(getEarthquakesSP());
}
return splitter;
}
public Set<IEvent> getEverSelectedEarthquakes() {
return everSelectedEarthquakes;
}
public Set<String> getEverSelectedPhases() {
return everSelectedPhases;
}
public void setEverSelectedPhases(Set<IEvent> earthquakes, Set<String> phases) {
logger.debug("setting selected values");
everSelectedEarthquakes = earthquakes;
everSelectedPhases = phases;
}
public void addEverSelectedPhases(Set<IEvent> earthquakes, Set<String> phases) {
logger.debug("adding selected values");
everSelectedEarthquakes = earthquakes;
everSelectedPhases.addAll(phases);
}
/**
* we must call with method after time scale changes in graph panel
*/
public void refreshAvailableEarthQuakes() {
logger.debug("refreshing earthquakes");
init = true;
earthquakesL.setListData(graphPanel.getAvailableEarthquakes());
earthquakesL.setSelectedValues(getEverSelectedEarthquakes().toArray(), false);
refreshAvailablePhases();
init = false;
}
/**
* this method called after changing selected earthquakes list
*/
@SuppressWarnings("deprecation")
private void refreshAvailablePhases() {
logger.debug("refreshing phases");
init = true;
phasesL.setListData(graphPanel.getAvailablePhases(earthquakesL.getSelectedValues()));
phasesL.setSelectedValues(getEverSelectedPhases().toArray(), false);
init = false;
}
/**
* This method is required by ListSelectionListener.
*/
@SuppressWarnings("deprecation")
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false && !init) {
if (e.getSource().equals(earthquakesL)) {
refreshAvailablePhases();
}
Set<IEvent> le = new HashSet<IEvent>();
for (Object o: earthquakesL.getSelectedValues()) {
le.add((IEvent) o);
}
Set<String> lp = new HashSet<String>();
for (Object o: phasesL.getSelectedValues()) {
lp.add((String) o);
}
if (e.getSource().equals(earthquakesL)) {
addEverSelectedPhases(le, lp);
} else {
setEverSelectedPhases(le, lp);
}
graphPanel.setSelectedPhases(le, lp);
}
}
private class PhaseList extends JList<Object> {
private static final long serialVersionUID = 1L;
public PhaseList() {
super();
init();
}
public PhaseList(Object[] listData) {
super(listData);
init();
}
private void init() {
setBackground(XMAXframe.getInstance().getBackground());
}
/**
* Selects the specified array of objects from the list.
*
* @param objects
* the array if objects to select
* @param shouldScroll
* {@code true} if the list should scroll to display the selected object, if one
* exists; otherwise {@code false}
*/
public void setSelectedValues(Object[] objects, boolean shouldScroll) {
if (objects == null) {
setSelectedIndex(-1);
} else {
int i, c;
clearSelection();
ListModel<Object> dm = getModel();
for (Object object: objects) {
for (i = 0, c = dm.getSize(); i < c; i++) {
if (object.equals(dm.getElementAt(i))) {
this.addSelectionInterval(i, i);
if (shouldScroll) {
ensureIndexIsVisible(i);
}
}
}
}
}
repaint();
}
}
private class EarthquakeCellRenderer extends JLabel implements ListCellRenderer<Object> {
private static final long serialVersionUID = 1L;
public Component getListCellRendererComponent(JList<?> list, // the list
Object value, // value to display
int index, // cell index
boolean isSelected, // is the cell selected
boolean cellHasFocus) // does the cell have focus
{
Earthquake earthquake = (Earthquake) value;
setText(earthquake.getSourceCode());
setToolTipText("<html>" + df.format(earthquake.getStartTime()) + "<br><i>Long </i>" + earthquake.getLongitude() + "<br><i>Lat </i>"
+ earthquake.getLatitude() + "<br><i>Depth </i>" + earthquake.getDepth() + "<br><i>Mag1 </i>" + earthquake.getMagnitude_mb()
+ "<br><i>Mag2 </i>" + earthquake.getMagnitude_MS() + "<br>" + earthquake.getLocation() + "</html>");
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
return this;
}
}
}