001/* A tab pane to display sensor data. 002 * 003 * Copyright (c) 2010 The Regents of the University of California. 004 * All rights reserved. 005 * 006 * '$Author: crawl $' 007 * '$Date: 2010-06-03 16:45:10 -0700 (Thu, 03 Jun 2010) $' 008 * '$Revision: 24730 $' 009 * 010 * Permission is hereby granted, without written agreement and without 011 * license or royalty fees, to use, copy, modify, and distribute this 012 * software and its documentation for any purpose, provided that the above 013 * copyright notice and the following two paragraphs appear in all copies 014 * of this software. 015 * 016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 020 * SUCH DAMAGE. 021 * 022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 027 * ENHANCEMENTS, OR MODIFICATIONS. 028 * 029 */ 030 031package org.kepler.gui; 032 033import java.awt.GridBagConstraints; 034import java.awt.GridBagLayout; 035import java.awt.event.ActionEvent; 036import java.awt.event.ActionListener; 037import java.lang.reflect.Field; 038import java.lang.reflect.InvocationTargetException; 039import java.lang.reflect.Method; 040import java.util.ArrayList; 041import java.util.List; 042 043import javax.swing.BorderFactory; 044import javax.swing.BoxLayout; 045import javax.swing.JButton; 046import javax.swing.JComponent; 047import javax.swing.JOptionPane; 048import javax.swing.JPanel; 049import javax.swing.JScrollPane; 050import javax.swing.SwingUtilities; 051 052import org.jfree.data.time.TimePeriodValues; 053import org.jfree.data.time.TimePeriodValuesCollection; 054import org.kepler.plotting.Plot; 055 056import ptolemy.actor.gui.TableauFrame; 057import ptolemy.kernel.util.IllegalActionException; 058import ptolemy.kernel.util.NameDuplicationException; 059import ptolemy.kernel.util.NamedObj; 060 061/** A tab pane to display sensor data. 062 * 063 * @author Daniel Crawl 064 * @version $Id: PlotsPanel.java 24730 2010-06-03 23:45:10Z crawl $ 065 */ 066public class PlotsPanel extends JPanel implements TabPane 067{ 068 /** Construct a new PlotsPanel in a frame with a specific title. */ 069 public PlotsPanel(TableauFrame parent, String title) 070 { 071 super(); 072 _title = title; 073 _frame = parent; 074 setBackground(TabManager.BGCOLOR); 075 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 076 panel = new JPanel(); 077 panel.setLayout(new GridBagLayout()); 078 panel.scrollRectToVisible(getVisibleRect()); 079 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 080 scrollPane = new JScrollPane(panel); 081 scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 082 scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 083 } 084 085 /** Get the container frame. */ 086 public TableauFrame getParentFrame() 087 { 088 return _frame; 089 } 090 091 /** Get the name of the tab. */ 092 public String getTabName() 093 { 094 return _title; 095 } 096 097 /** Initialize the contents of the tab. */ 098 public void initializeTab() throws Exception 099 { 100 101// System.out.println("initializeTab() PlotsPanel"); 102 this.add(scrollPane); 103 } 104 105 public Plot addGraph() { 106 final JComponent me = panel; 107 final Plot plot = createPlot(); 108 SwingUtilities.invokeLater(new Runnable() { 109 public void run() { 110 GridBagConstraints gbc = new GridBagConstraints(); 111 gbc.gridx = 0; 112 gbc.gridy = GridBagConstraints.RELATIVE; 113 JPanel chart = plot.getPanel(); 114 chart.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); 115 me.add(chart, gbc); 116 DoubleCheckButton clearButton = new DoubleCheckButton("Clear", "Are you sure you want to clear this graph?"); 117 clearButton.addActionListener(new ActionListener() { 118 public void actionPerformed(ActionEvent e) { 119 TimePeriodValuesCollection dataset = plot.getDataset(); 120 for (int i = 0; i < dataset.getSeriesCount(); i++) { 121 // Evil black magic 122 // This is required to remove accumulated data 123 // while still maintaining the data structures 124 // so future points can be plotted for these 125 // lines. 126 TimePeriodValues series = dataset.getSeries(i); 127 try { 128 Field dataField = series.getClass().getDeclaredField("data"); 129 dataField.setAccessible(true); 130 List dataList = (List) dataField.get(series); 131 dataList.clear(); 132 Method method = series.getClass().getDeclaredMethod("recalculateBounds"); 133 method.setAccessible(true); 134 method.invoke(series); 135 } 136 catch(InvocationTargetException e1) { 137 e1.printStackTrace(); 138 } 139 catch(NoSuchMethodException e1) { 140 e1.printStackTrace(); 141 } 142 catch(IllegalAccessException e1) { 143 e1.printStackTrace(); 144 } 145 catch(NoSuchFieldException e1) { 146 e1.printStackTrace(); 147 } 148 series.fireSeriesChanged(); // Can do this normally at least. 149 } 150 } 151 }); 152 plot.setClearButton(clearButton); 153 me.add(clearButton, gbc); 154 me.repaint(); 155 me.revalidate(); 156 } 157 }); 158 return plot; 159 } 160 161 private Plot createPlot() { 162 Plot plot = new Plot(_frame); 163 _plots.add(plot); 164 return plot; 165 } 166 167// private boolean isEmpty() { 168// return _plots.isEmpty(); 169// } 170 171 private final List<Plot> _plots = new ArrayList<Plot>(); 172 173 /** Set the frame for this tab. */ 174 public void setParentFrame(TableauFrame parent) 175 { 176 _frame = parent; 177 } 178 179 /** A factory to create PlotsPanels. */ 180 public static class ViewerFactory extends TabPaneFactory 181 { 182 /** 183 * Create a factory with the given name and container. 184 * 185 *@param container 186 * The container. 187 *@param name 188 * The name of the entity. 189 *@exception IllegalActionException 190 * If the container is incompatible with this attribute. 191 *@exception NameDuplicationException 192 * If the name coincides with an attribute already in the 193 * container. 194 */ 195 public ViewerFactory(NamedObj container, String name) 196 throws IllegalActionException, NameDuplicationException { 197 super(container, name); 198 } 199 200 /** Create a tab pane in a frame. */ 201 public TabPane createTabPane(TableauFrame parent) { 202 return new PlotsPanel(parent, "Plot Viewer"); 203 } 204 } 205 206 private TableauFrame _frame; 207 private String _title; 208 private JScrollPane scrollPane; 209 private JPanel panel; 210 211 private class DoubleCheckButton extends JButton { 212 public DoubleCheckButton(String initialText, String confirmText) { 213 super(initialText); 214 this.confirmText = confirmText; 215 } 216 217 218 @Override 219 protected void fireActionPerformed(ActionEvent event) { 220 int response = JOptionPane.showConfirmDialog(null, confirmText, "Confirm", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); 221 if (response == JOptionPane.YES_OPTION) { 222 super.fireActionPerformed(event); 223 } 224 } 225 226 private String confirmText = null; 227 } 228}