package com.ibm.nmon.gui.interval; import java.awt.BorderLayout; import java.awt.KeyboardFocusManager; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.BoxLayout; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTabbedPane; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import com.ibm.nmon.gui.GUIDialog; import com.ibm.nmon.gui.Styles; import com.ibm.nmon.gui.file.IntervalFileChooser; import com.ibm.nmon.gui.main.NMONVisualizerGui; import com.ibm.nmon.gui.time.SystemTimeList; import com.ibm.nmon.gui.time.SystemTimeTableModel; import com.ibm.nmon.gui.util.TimeZoneComboBox; import com.ibm.nmon.interval.Interval; import com.ibm.nmon.interval.IntervalListener; import com.ibm.nmon.interval.IntervalManager; import com.ibm.nmon.data.DataSet; /** * Dialog to allow adding and removing of Intervals. */ public final class IntervalManagerDialog extends GUIDialog implements IntervalListener { private static final long serialVersionUID = 4964215301504994528L; private final IntervalList intervals; private final SystemTimeList systemTimes; private final AbsoluteTimeIntervalPanel absolute; private final RelativeTimeIntervalPanel relative; private final BulkIntervalPanel bulk; private final TimeZoneComboBox timeZones; private final JButton save; private IntervalFileChooser fileChooser; public IntervalManagerDialog(NMONVisualizerGui gui) { super(gui, gui.getMainFrame(), "Manage Intervals"); setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS)); setIconImage(Styles.INTERVAL_ICON.getImage()); timeZones = new TimeZoneComboBox(gui.getDisplayTimeZone()); timeZones.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { IntervalManagerDialog.this.gui.setDisplayTimeZone(timeZones.getSelectedTimeZone()); } }); JPanel timePanel = new JPanel(); JLabel label = new JLabel("Time Zone:"); label.setHorizontalAlignment(SwingConstants.TRAILING); label.setFont(Styles.LABEL); timePanel.add(label); timePanel.add(timeZones); AbstractAction loadAction = new AbstractAction() { private static final long serialVersionUID = -8590641369327623520L; @Override public void actionPerformed(ActionEvent e) { if (fileChooser == null) { fileChooser = new IntervalFileChooser(IntervalManagerDialog.this.gui); } fileChooser.load(); } }; JButton load = new JButton("Load"); load.addActionListener(loadAction); AbstractAction saveAction = new AbstractAction() { private static final long serialVersionUID = 8726615183618542317L; @Override public void actionPerformed(ActionEvent e) { if (fileChooser == null) { fileChooser = new IntervalFileChooser(IntervalManagerDialog.this.gui); } fileChooser.save(); } }; save = new JButton("Save") { private static final long serialVersionUID = 4862470165493725505L; public void setEnabled(boolean b) { // only associate keyboard shortcut when save is enabled super.setEnabled(b); if (b) { ((JPanel) getContentPane()).getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), "save"); } else { ((JPanel) getContentPane()).getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .remove(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)); } }; }; save.setIcon(Styles.SAVE_ICON); save.addActionListener(saveAction); JPanel buttons = new JPanel(); buttons.add(load); buttons.add(save); JPanel filler = new JPanel(); filler.setPreferredSize(buttons.getPreferredSize()); JPanel temp = new JPanel(new BorderLayout()); temp.add(filler, BorderLayout.LINE_START); temp.add(timePanel, BorderLayout.CENTER); temp.add(buttons, BorderLayout.LINE_END); add(temp); absolute = new AbsoluteTimeIntervalPanel(gui); relative = new RelativeTimeIntervalPanel(gui); bulk = new BulkIntervalPanel(gui); JTabbedPane tabs = new JTabbedPane(); // note change the order here => change the hack in setVisible() for the listeners tabs.add("Absolute", absolute); tabs.add("Relative", relative); tabs.add("Bulk", bulk); tabs.setMnemonicAt(0, java.awt.event.KeyEvent.VK_B); tabs.setMnemonicAt(1, java.awt.event.KeyEvent.VK_R); tabs.setMnemonicAt(2, java.awt.event.KeyEvent.VK_A); add(tabs); intervals = new IntervalList(gui); intervals.setBorder(Styles.DOUBLE_LINE_BORDER); add(intervals); systemTimes = new SystemTimeList(gui); add(systemTimes); tabs.addChangeListener(timeSynchronizer); systemTimes.getTable().addMouseListener(systemTimesMenu); intervals.getTable().addMouseListener(intervalsMenu); // clean up internal listeners when this dialog closes addHierarchyListener(intervals); addHierarchyListener(systemTimes); // when an interval is clicked or the start and end times are updated, // update the system times intervals.addPropertyChangeListener("interval", systemTimes); // also update system times when the current data is changed absolute.addPropertyChangeListener("interval", systemTimes); relative.addPropertyChangeListener("interval", systemTimes); bulk.addPropertyChangeListener("interval", systemTimes); // keep the system times in sync with the current start and end times KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", focusManager); JPanel content = (JPanel) getContentPane(); ActionMap actions = content.getActionMap(); InputMap inputs = content.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); actions.put("load", loadAction); actions.put("save", saveAction); inputs.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK), "load"); } @Override public void setVisible(boolean b) { super.setVisible(b); // ensure the start field for absolute requests focus if (true) { // hack to toggle state so the first interval panel actually has its listeners set absolute.setEnabled(false); absolute.setEnabled(true); relative.setEnabled(false); bulk.setEnabled(false); save.setEnabled(gui.getIntervalManager().getIntervalCount() != 0); gui.getIntervalManager().addListener(this); } // do not handle false; assume dialog is only opened once not opened and closed } @Override public void dispose() { super.dispose(); gui.getIntervalManager().removeListener(this); KeyboardFocusManager.getCurrentKeyboardFocusManager().removePropertyChangeListener("focusOwner", focusManager); // clean up listeners absolute.setEnabled(false); relative.setEnabled(false); bulk.setEnabled(false); } @Override public void intervalAdded(Interval interval) { save.setEnabled(true); } @Override public void intervalRemoved(Interval interval) { save.setEnabled(gui.getIntervalManager().getIntervalCount() != 0); } @Override public void intervalsCleared() { save.setEnabled(false); } @Override public void currentIntervalChanged(Interval interval) { intervals.repaint(); } @Override public void intervalRenamed(Interval interval) { intervals.repaint(); } // display a menu on the system times table that allows the user to set the current interval or // start and end times private final MouseAdapter intervalsMenu = new MouseAdapter() { public void mousePressed(MouseEvent e) { mouseReleased(e); } @Override public void mouseReleased(MouseEvent e) { int row = intervals.getTable().rowAtPoint(e.getPoint()); if (e.isPopupTrigger() && (row >= 0)) { intervals.getTable().changeSelection(row, 0, false, false); final Interval interval = ((IntervalTableModel) intervals.getTable().getModel()).getValueAt(row); JPopupMenu menu = new JPopupMenu(); JMenuItem item = null; item = new JMenuItem("Use as Start & End"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { BaseIntervalPanel active = null; if (absolute.isEnabled()) { active = absolute; } else if (relative.isEnabled()) { active = relative; } else if (bulk.isEnabled()) { active = bulk; } if (active != null) { active.setTimes(interval.getStart(), interval.getEnd()); active.revalidate(); } } }); menu.add(item); if (!interval.equals(gui.getIntervalManager().getCurrentInterval())) { item = new JMenuItem("Set as Current"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { gui.getIntervalManager().setCurrentInterval(interval); intervals.getTable().repaint(); } }); menu.add(item); } menu.addSeparator(); item = new JMenuItem("Rename"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { intervals.getTable().editCellAt(intervals.getTable().getSelectedRow(), 0); } }); menu.add(item); menu.addSeparator(); item = new JMenuItem("Remove"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { gui.getIntervalManager().removeInterval(interval); intervals.getTable().repaint(); } }); menu.add(item); menu.show(e.getComponent(), e.getX(), e.getY()); // clear the selected system just like when the system times table loses focus // this cannot be done in the focus listener since the interval table does not have // to gain focus for the menu to show up systemTimes.getTable().clearSelection(); } } }; // display a menu on the system times table that allows the user to set intervals or start and // end times private final MouseAdapter systemTimesMenu = new MouseAdapter() { public void mousePressed(MouseEvent e) { mouseReleased(e); } @Override public void mouseReleased(MouseEvent e) { int row = systemTimes.getTable().rowAtPoint(e.getPoint()); if (e.isPopupTrigger() && (row >= 0)) { systemTimes.getTable().changeSelection(row, 0, false, false); final DataSet data = ((SystemTimeTableModel) systemTimes.getTable().getModel()).getValueAt(row); JPopupMenu menu = new JPopupMenu(); JMenuItem item = new JMenuItem("Use as Start & End"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { BaseIntervalPanel active = null; if (absolute.isEnabled()) { active = absolute; } else if (relative.isEnabled()) { active = relative; } else if (bulk.isEnabled()) { active = bulk; } if (active != null) { active.setTimes(data.getStartTime(), data.getEndTime()); active.revalidate(); } } }); menu.add(item); item = new JMenuItem("Add Interval"); item.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { long startTime = data.getStartTime(); long endTime = data.getEndTime(); NMONVisualizerGui gui = IntervalManagerDialog.this.gui; // only add if not the default interval if ((startTime != gui.getMinSystemTime()) || (endTime != gui.getMaxSystemTime())) { IntervalManager intervalManager = gui.getIntervalManager(); // this interval should always be valid assuming the file times // are valid Interval i = new Interval(startTime, endTime); if (intervalManager.addInterval(i)) { firePropertyChange("interval", intervalManager.getCurrentInterval(), i); intervalManager.setCurrentInterval(i); } gui.getIntervalManager().addInterval(new Interval(startTime, endTime)); } } }); menu.add(item); menu.show(e.getComponent(), e.getX(), e.getY()); } } }; // when switching between absolute, relative and bulk, update the values so they stay in sync private final ChangeListener timeSynchronizer = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { BaseIntervalPanel previous = null; if (absolute.isEnabled()) { previous = absolute; } else if (relative.isEnabled()) { previous = relative; } else if (bulk.isEnabled()) { previous = bulk; } else { return; } JTabbedPane tabs = (JTabbedPane) e.getSource(); BaseIntervalPanel current = (BaseIntervalPanel) tabs.getSelectedComponent(); if (current != null) { current.setIntervalName(previous.getIntervalName()); current.setTimes(previous.getStartTime(), previous.getEndTime()); current.setEnabled(true); } // remove listeners previous.setEnabled(false); current.propertyChange(new PropertyChangeEvent(this, "timeZone", null, previous.getTimeZone())); } }; // when focus returns to the time panels, // set the system times interval to the start and end times private final PropertyChangeListener focusManager = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getNewValue() != null) { // absolute parent => tabs // if any of the data entry forms are selected, unselect the interval table if (SwingUtilities.isDescendingFrom((java.awt.Component) evt.getNewValue(), absolute.getParent())) { intervals.getTable().clearSelection(); systemTimes.getTable().clearSelection(); } else if (intervals.getTable() == evt.getNewValue()) { systemTimes.getTable().clearSelection(); } } } }; }