package com.ibm.nmon.gui.interval;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.util.TimeZone;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;
import com.ibm.nmon.gui.Styles;
import com.ibm.nmon.gui.main.NMONVisualizerGui;
import com.ibm.nmon.data.DataSetListener;
import com.ibm.nmon.data.DataSet;
import com.ibm.nmon.interval.IntervalManager;
import com.ibm.nmon.interval.Interval;
/**
* <p>
* Base implementation for a panel that supports entering times to create a new {@link Interval}.
* <ul>
* <li>Creates common labels, text fields and buttons for use by subclasses.</li>
* <li>Defines a common API for setting start and end times for the interval.</li>
* <li>Listens for {@link DataSetListener DataSet events} and updates the start and end times based
* on the new application min and max times.</li>
* </ul>
* <p>
*
* <p>
* Subclasses must implement
* {@link PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) propertyChange()}
* for <code>timeZone</code> events. When the time zone changes, the displayed start and end times
* should change to reflect the new time zone.
* </p>
*/
abstract class BaseIntervalPanel extends JPanel implements DataSetListener, PropertyChangeListener {
private static final long serialVersionUID = 5417848225227158133L;
protected final NMONVisualizerGui gui;
protected final JTextField name;
protected final JLabel nameLabel;
protected final JButton add;
protected final JButton reset;
protected final JButton endToStart;
BaseIntervalPanel(NMONVisualizerGui gui) {
super();
this.gui = gui;
name = new JTextField(10);
nameLabel = new JLabel("Interval Name:");
nameLabel.setHorizontalAlignment(SwingConstants.TRAILING);
nameLabel.setFont(Styles.LABEL);
add = new JButton("Add");
add.setIcon(Styles.ADD_ICON);
reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setTimes(getDefaultStartTime(), getDefaultEndTime());
}
});
AbstractAction endToStartAction = new AbstractAction() {
private static final long serialVersionUID = -5385099678909892027L;
@Override
public void actionPerformed(ActionEvent e) {
setStartToEnd();
}
};
endToStart = new JButton("Start = End");
endToStart.setIcon(Styles.buildIcon("arrow_up.png"));
endToStart.addActionListener(endToStartAction);
ActionMap actions = getActionMap();
InputMap inputs = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actions.put("endToStart", endToStartAction);
inputs.put(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK), "endToStart");
}
final String getIntervalName() {
return name.getText();
}
final void setIntervalName(String name) {
this.name.setText(name);
}
/**
* @return a default value for the start time, in milliseconds
*
* @see {@link NMONVisualizerApp#getMinSystemTime()}
*/
protected final long getDefaultStartTime() {
if (gui.getDataSetCount() > 0) {
return gui.getMinSystemTime();
}
else {
// rounding off milliseconds
return ((System.currentTimeMillis() / 1000) - (86400 / 2)) * 1000;
}
}
/**
* @return a default value for the end time, in milliseconds
*
* @see {@link NMONVisualizerApp#getMaxSystemTime()}
*/
protected final long getDefaultEndTime() {
if (gui.getDataSetCount() > 0) {
return gui.getMaxSystemTime();
}
else {
// rounding off milliseconds
return ((System.currentTimeMillis() / 1000) + (86400 / 2)) * 1000;
}
}
/**
* @return the currently set start time, in milliseconds
*/
abstract long getStartTime();
/**
* @return the currently set end time, in milliseconds
*/
abstract long getEndTime();
/**
* Set the start and end times using milliseconds
*/
abstract void setTimes(long start, long end);
/**
* Get the current time zone used for formatting displayed time values.
*/
abstract TimeZone getTimeZone();
/**
* Set the current end time to the current end time. This will not be a valid interval since the
* start time will now equal the end time.
*/
protected abstract void setStartToEnd();
@Override
public void setEnabled(boolean enabled) {
if (isEnabled() != enabled) {
super.setEnabled(enabled);
if (enabled) {
gui.addDataSetListener(this);
gui.addPropertyChangeListener("timeZone", this);
getRootPane().setDefaultButton(add);
}
else {
gui.removeDataSetListener(this);
gui.removePropertyChangeListener("timeZone", this);
getRootPane().setDefaultButton(null);
}
}
}
public final void dataAdded(DataSet file) {
setTimes(getDefaultStartTime(), getDefaultEndTime());
}
public final void dataRemoved(DataSet data) {
setTimes(getDefaultStartTime(), getDefaultEndTime());
}
public final void dataChanged(DataSet data) {
setTimes(getDefaultStartTime(), getDefaultEndTime());
}
public final void dataCleared() {
setTimes(getDefaultStartTime(), getDefaultEndTime());
}
protected final void requestFocus(final JFormattedTextField field) {
field.requestFocus();
// hack to fix formatted text fields receiving focus programatically but not allowing
// formatted edits
try {
field.commitEdit();
}
catch (java.text.ParseException pe) {
// ignore - value should be valid since formatter checked when focus was previously lost
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
field.selectAll();
}
});
}
/**
* <p>
* Used by subclasses to allow multiple components to add a new interval.
* </p>
*
* <p>
* Fires an <code>interval</code> property change event and calls
* {@link IntervalManager#setCurrentInterval(Interval) setCurrentInterval()} when an interval is
* added.
* </p>
*/
protected final ActionListener addInterval = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
long startTime = getStartTime();
long endTime = getEndTime();
// only add if not the default interval
if ((startTime != gui.getMinSystemTime()) || (endTime != gui.getMaxSystemTime())) {
IntervalManager intervalManager = gui.getIntervalManager();
Interval i = null;
try {
i = new Interval(startTime, endTime);
i.setName(name.getText());
}
catch (IllegalArgumentException iae) {
JOptionPane.showMessageDialog(BaseIntervalPanel.this.getParent(), "Start time"
+ " must be less than " + " End time", "Invalid Time", JOptionPane.ERROR_MESSAGE);
return;
}
if (intervalManager.addInterval(i)) {
firePropertyChange("interval", intervalManager.getCurrentInterval(), i);
intervalManager.setCurrentInterval(i);
}
}
}
};
}