KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mc4j > console > swing > graph > AbstractGraphPanel


1 /*
2  * Copyright 2002-2004 Greg Hinkle
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.mc4j.console.swing.graph;
18
19 import org.jfree.chart.ChartPanel;
20 import org.jfree.chart.JFreeChart;
21 import org.jfree.chart.axis.DateAxis;
22 import org.jfree.chart.axis.LogarithmicAxis;
23 import org.jfree.chart.axis.NumberAxis;
24 import org.jfree.chart.plot.XYPlot;
25 import org.jfree.chart.renderer.xy.DefaultXYItemRenderer;
26 import org.jfree.chart.title.TextTitle;
27 import org.jfree.data.time.Millisecond;
28 import org.jfree.data.time.TimeSeries;
29 import org.jfree.data.time.TimeSeriesCollection;
30 import org.mc4j.console.dashboard.components.RefreshControlComponent;
31 import org.mc4j.console.swing.LogarithmicTimeJSlider;
32 import org.openide.windows.TopComponent;
33
34 import javax.swing.*;
35 import javax.swing.border.LineBorder JavaDoc;
36 import java.awt.BorderLayout JavaDoc;
37 import java.awt.Color JavaDoc;
38 import java.awt.Dimension JavaDoc;
39 import java.awt.FlowLayout JavaDoc;
40 import java.awt.Font JavaDoc;
41 import java.awt.event.ActionEvent JavaDoc;
42 import java.awt.event.ActionListener JavaDoc;
43 import java.awt.event.WindowAdapter JavaDoc;
44 import java.awt.event.WindowEvent JavaDoc;
45 import java.util.Calendar JavaDoc;
46 import java.util.Date JavaDoc;
47 import java.util.GregorianCalendar JavaDoc;
48 import java.util.HashMap JavaDoc;
49 import java.util.Map JavaDoc;
50 import java.util.Timer JavaDoc;
51 import java.util.TimerTask JavaDoc;
52 import java.util.Set JavaDoc;
53
54 /**
55  * This is an abstract base class for dynamic, running Graphs in MC4J. This
56  * includes a base set of features like an included timer for adding
57  * observations and a popup toolbox of chart controls to dynamically change
58  * how the chart is displaying.
59  *
60  * @author Greg Hinkle (ghinkle@users.sourceforge.net), September 2002
61  * @version $Revision: 573 $($Author: ghinkl $ / $Date: 2006-04-17 08:01:27 -0400 (Mon, 17 Apr 2006) $)
62  */

63 public abstract class AbstractGraphPanel<T> extends TopComponent {
64
65
66     protected TimeSeriesCollection dataset = new TimeSeriesCollection();
67
68     protected JFreeChart chart;
69     protected Timer JavaDoc dataGeneratorTimer;
70     protected TimerTask JavaDoc dataGeneratorTimerTask;
71
72     protected Map JavaDoc<T,TimeSeries> timeSeriesMap = new HashMap JavaDoc<T, TimeSeries>();
73     protected XYPlot xyplot;
74
75
76     // These properties build and manage the control popup for the graph
77
private JCheckBox controlsButton;
78     private JPanel controlsPanel;
79
80     private ButtonGroup buttonGroupScale;
81     private ButtonGroup buttonGroupTimeRange;
82     private JRadioButton jRadioButtonScaleLinear;
83     private JRadioButton jRadioButtonScaleLogarithmic;
84     private JRadioButton jRadioTimeHours;
85     private JRadioButton jRadioTimeMinutes;
86     private JRadioButton jRadioTimeSeconds;
87     protected LogarithmicTimeJSlider sleepSlider;
88     protected JLabel sleepDelay;
89
90
91     /** Manages if the component is removed and re-added to a container */
92     private boolean removed = false;
93
94     protected int failures = 0;
95     protected static final int MAX_FAILURES = 10;
96     protected ChartPanel chartPanel;
97
98
99     public AbstractGraphPanel() {
100         setDoubleBuffered(false);
101         initGraphPanel();
102     }
103
104     public int getPersistenceType() {
105         return TopComponent.PERSISTENCE_NEVER;
106     }
107
108     public String JavaDoc getChartTitle() {
109         return chart.getTitle().getText();
110     }
111     public void setChartTitle(final String JavaDoc name) {
112         SwingUtilities.invokeLater(new Runnable JavaDoc() {
113             public void run() {
114                 setName(name);
115             }
116         });
117
118          chart.setTitle(
119             new TextTitle(name,
120             new Font JavaDoc("SansSerif",Font.BOLD, 12)));
121
122     }
123
124     protected void initGraphPanel() {
125
126         setPreferredSize(new Dimension JavaDoc(500,450));
127
128         DateAxis domain = new DateAxis("Time");
129         NumberAxis range = new NumberAxis("");
130
131         this.xyplot = new XYPlot();
132         this.xyplot.setDataset(dataset);
133         this.xyplot.setDomainAxis(domain);
134         this.xyplot.setRangeAxis(range);
135         DefaultXYItemRenderer renderer = new DefaultXYItemRenderer();
136         renderer.setShapesVisible(false);
137         this.xyplot.setRenderer(renderer);
138
139         domain.setAutoRange(true);
140         domain.setLowerMargin(0.0);
141         domain.setUpperMargin(0.0);
142         domain.setTickLabelsVisible(true);
143
144         range.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
145
146         this.chart =
147             new JFreeChart(
148                 "",
149                 JFreeChart.DEFAULT_TITLE_FONT,
150                 xyplot,
151                 true);
152
153 // chart.setTitle(
154
// new TextTitle("Graph ???",
155
// new Font("SansSerif",Font.BOLD, 12)));
156

157         chartPanel = new ChartPanel(chart,false,true,true,false,false);
158         //chartPanel.setPopupMenu(null);
159
chartPanel.setOpaque(true);
160         chartPanel.setDoubleBuffered(false);
161         chart.setBackgroundPaint(this.getBackground());
162         chartPanel.setBackground(this.getBackground());
163         chartPanel.setBorder(new LineBorder JavaDoc(Color.BLACK,1));
164
165         setLayout(new BorderLayout JavaDoc());
166         setOpaque(false);
167         add(chartPanel,BorderLayout.CENTER);
168
169         buildGraphControls();
170
171         ControlsPopupButton dataButton = new ControlsPopupButton(new GraphSeriesPanel(dataset),"images/GraphElements.gif");
172         this.controlsButton = new ControlsPopupButton(this.controlsPanel,"images/GraphSettings2.gif");
173
174         JPanel northPanel = new JPanel(new FlowLayout JavaDoc(FlowLayout.RIGHT));
175         northPanel.add(dataButton);
176         northPanel.add(this.controlsButton);
177         northPanel.setOpaque(false);
178         add(northPanel,BorderLayout.NORTH);
179         this.controlsPanel.setLocation(5,5);
180
181         doLayout();
182         repaint();
183     }
184
185
186     /**
187      * A custom JCheckBox that will popup the controls toolbox for the chart
188      */

189     public static class ControlsPopupButton extends JCheckBox {
190
191         private JPopupMenu popup;
192         private Icon icon;// = createImageIcon("images/GraphSettings2.gif");
193

194         private JComponent payload;
195
196         public ControlsPopupButton(JComponent payload, String JavaDoc img) {
197             this.payload = payload;
198             this.icon = createImageIcon(img);
199
200             setIcon(icon);
201             setOpaque(false);
202             init();
203         }
204
205         /** Returns an ImageIcon, or null if the path was invalid. */
206         protected ImageIcon createImageIcon(String JavaDoc path) {
207             java.net.URL JavaDoc imgURL = RefreshControlComponent.class.getClassLoader().getResource(path);
208             if (imgURL != null) {
209                 return new ImageIcon(imgURL);
210             } else {
211                 System.err.println("Couldn't find file: " + path);
212                 return null;
213             }
214         }
215
216         public void showPopup() {
217             GlassWindow.show(this.payload, this);
218             //JXGlassBox gb = new JXGlassBox(0.8f);
219
// gb.add(this.payload);
220
// gb.setDismissOnClick(true);
221
// gb.setVisible(true);
222
// gb.showOnGlassPane((Container) this.getRootPane().getGlassPane(),this.getX() - this.payload.getWidth(), this.getY() + this.getHeight());
223
// if (popup == null) {
224
// popup = new JPopupMenu();
225
// popup.add(this.payload);
226
// }
227
// popup.show(this, 0, this.getHeight());
228
}
229
230         private void init() {
231             addActionListener(new ActionListener JavaDoc() {
232                 public void actionPerformed(ActionEvent JavaDoc e) {
233                     showPopup();
234                 }
235             });
236         }
237     }
238
239
240
241     public long getUpdateDelay() {
242         if (sleepSlider != null)
243             return sleepSlider.getValue();
244         else
245             return 1000L;
246     }
247
248     /**
249      * Cancels any existing scheduled task and reschedules for the
250      * current status of the delay control.
251      */

252     public void reschedule() {
253         if (this.dataGeneratorTimer == null) {
254             this.dataGeneratorTimer = new Timer JavaDoc();
255         }
256
257         if (this.dataGeneratorTimerTask != null) {
258             try {
259                 this.dataGeneratorTimerTask.cancel();
260             } catch(Exception JavaDoc e) { e.printStackTrace();}
261         }
262
263         this.dataGeneratorTimer.schedule(
264             this.dataGeneratorTimerTask = getDataGeneratorTask(),
265             getUpdateDelay(),
266             getUpdateDelay());
267
268     }
269
270     /**
271      * Stops taking measurements for the graph.
272      */

273     public void pauseSchedule() {
274         this.dataGeneratorTimerTask.cancel();
275         this.dataGeneratorTimerTask = null;
276     }
277
278
279     protected TimerTask JavaDoc getDataGeneratorTask() {
280         return new DataGenerator();
281     }
282
283
284     public void addNotify() {
285         super.addNotify();
286         if (removed) {
287             reschedule();
288             this.removed = false;
289         }
290     }
291
292
293     public void removeNotify() {
294         super.removeNotify();
295         if (this.dataGeneratorTimer != null)
296             this.dataGeneratorTimer.cancel();
297         this.dataGeneratorTimer = null;
298         this.removed = true;
299     }
300
301
302
303     /**
304      * Define this graph as logarithmic or not
305      * @param logarithmic if true, graph will be logarithmic,
306      * otherwise it will be linear
307      */

308     public void setLogarithmic(boolean logarithmic) {
309         if (logarithmic) {
310             try {
311                 this.xyplot.setRangeAxis(new LogarithmicAxis(""));
312             } catch(Exception JavaDoc e) {
313                 // In case we try to use a logarithmic axis when the values go below 1
314
this.xyplot.setRangeAxis(new NumberAxis(""));
315             }
316         } else {
317             this.xyplot.setRangeAxis(new NumberAxis(""));
318         }
319     }
320
321     public void setBackground(Color JavaDoc bg) {
322         super.setBackground(bg);
323         //this.sleepSlider.setBackground(bg);
324
}
325
326     public void updateRange() {
327         DateAxis dateAxis = (DateAxis) this.xyplot.getDomainAxis();
328
329         Calendar JavaDoc start = new GregorianCalendar JavaDoc();
330
331         start.setTime(new Date JavaDoc());
332
333         if (this.jRadioTimeSeconds.isSelected()) {
334             start.add(Calendar.SECOND, -60);
335         } else if (this.jRadioTimeMinutes.isSelected()) {
336             //this.sleepSlider.setEnabled(false);
337
start.add(Calendar.MINUTE, -60);
338         } else if (this.jRadioTimeHours.isSelected()) {
339             start.add(Calendar.HOUR, -48);
340         }
341
342         // this is a hack to slow down the data gathering for the longer periods...
343
// TODO GH: Build a TimeSeries that modulates the time periods automatically
344
// i.e.
345
// | Seconds | Minutes | Hours |
346
// ***************** * * * * * * * * * * * * *
347
if (this.jRadioTimeMinutes.isSelected()) {
348             sleepSlider.setValue(10000);
349         } else if (this.jRadioTimeHours.isSelected()) {
350             sleepSlider.setValue(100000);
351         }
352
353
354         dateAxis.setRange(start.getTime(),new Date JavaDoc());
355     }
356
357
358     protected JPanel buildGraphControls() {
359
360         this.controlsPanel = new JPanel();
361         //this.controlsPanel.setBorder(BorderFactory.createLineBorder(Color.black));
362
this.controlsPanel.setLayout(new BoxLayout(this.controlsPanel,BoxLayout.X_AXIS));
363
364         // Seconds, Minutes, Hours
365
JPanel timeDurationPanel = new JPanel();
366         timeDurationPanel.setLayout(new BoxLayout(timeDurationPanel, BoxLayout.Y_AXIS));
367         timeDurationPanel.setBorder(BorderFactory.createTitledBorder("Time Range"));
368
369         buttonGroupTimeRange = new javax.swing.ButtonGroup JavaDoc();
370
371         jRadioTimeSeconds = new javax.swing.JRadioButton JavaDoc("seconds", true);
372         jRadioTimeSeconds.setToolTipText("Track the graph for 60 seconds");
373         jRadioTimeSeconds.setOpaque(false);
374
375         jRadioTimeMinutes = new javax.swing.JRadioButton JavaDoc("minutes", false);
376         jRadioTimeMinutes.setToolTipText("Track this graph for 60 minutes.");
377         jRadioTimeMinutes.setOpaque(false);
378
379         jRadioTimeHours = new javax.swing.JRadioButton JavaDoc("hours", false);
380         jRadioTimeHours.setToolTipText("Track this graph for 48 hours.");
381         jRadioTimeHours.setOpaque(false);
382
383         buttonGroupTimeRange.add(jRadioTimeSeconds);
384         buttonGroupTimeRange.add(jRadioTimeMinutes);
385         buttonGroupTimeRange.add(jRadioTimeHours);
386
387         timeDurationPanel.add(jRadioTimeSeconds);
388         timeDurationPanel.add(jRadioTimeMinutes);
389         timeDurationPanel.add(jRadioTimeHours);
390
391         // Scale (linear vs. logarithmic)
392
JPanel timeScalePanel = new JPanel();
393         timeScalePanel.setLayout(new BoxLayout(timeScalePanel, BoxLayout.Y_AXIS));
394         timeScalePanel.setBorder(BorderFactory.createTitledBorder("Time Scale"));
395
396         buttonGroupScale = new javax.swing.ButtonGroup JavaDoc();
397
398         jRadioButtonScaleLinear = new javax.swing.JRadioButton JavaDoc("Linear", true);
399         jRadioButtonScaleLinear.setOpaque(false);
400
401         jRadioButtonScaleLogarithmic = new javax.swing.JRadioButton JavaDoc("Logarithmic", false);
402         jRadioButtonScaleLogarithmic.setOpaque(false);
403
404         buttonGroupScale.add(jRadioButtonScaleLinear);
405         buttonGroupScale.add(jRadioButtonScaleLogarithmic);
406
407         timeScalePanel.add(jRadioButtonScaleLinear);
408         timeScalePanel.add(jRadioButtonScaleLogarithmic);
409
410         // Update speed (in milleseconds)
411
JPanel updateSpeedPanel = new JPanel();
412         updateSpeedPanel.setLayout(new BoxLayout(updateSpeedPanel, BoxLayout.Y_AXIS));
413         updateSpeedPanel.setBorder(BorderFactory.createTitledBorder("Update Speed"));
414
415         //sleepSlider = new javax.swing.JSlider(100,10000,1000);
416
//sleepSlider.setPaintLabels(true);
417
//sleepSlider.setPaintTicks(true);
418
//sleepSlider.setMinorTickSpacing(500);
419
//sleepSlider.setMajorTickSpacing(2000);
420

421         sleepSlider = new LogarithmicTimeJSlider(100, 100000, 1000);
422
423         sleepSlider.setPaintTicks(true);
424         sleepSlider.setPaintLabels(true);
425         sleepSlider.setMajorTickSpacing(10);
426         sleepSlider.setMinorTickSpacing(10);
427
428         sleepSlider.setToolTipText("Time between updates");
429         sleepSlider.setOpaque(false);
430
431         sleepDelay = new JLabel("Delay: " + sleepSlider.getTime());
432
433         sleepSlider.addChangeListener(new javax.swing.event.ChangeListener JavaDoc() {
434             public void stateChanged(javax.swing.event.ChangeEvent JavaDoc evt) {
435                 sleepSliderPropertyChange(null);
436                 sleepDelay.setText("Delay: " + sleepSlider.getTime());
437             }
438         });
439
440
441         updateSpeedPanel.add(sleepSlider);
442         updateSpeedPanel.add(sleepDelay);
443
444         jRadioButtonScaleLinear.addChangeListener(new javax.swing.event.ChangeListener JavaDoc() {
445             public void stateChanged(javax.swing.event.ChangeEvent JavaDoc evt) {
446                 scaleChanged(evt);
447             }
448         });
449
450         jRadioButtonScaleLogarithmic.addChangeListener(new javax.swing.event.ChangeListener JavaDoc() {
451             public void stateChanged(javax.swing.event.ChangeEvent JavaDoc evt) {
452                 scaleChanged(evt);
453             }
454         });
455
456
457         this.controlsPanel.add(timeDurationPanel);
458         this.controlsPanel.add(updateSpeedPanel);
459         this.controlsPanel.add(timeScalePanel);
460
461         return this.controlsPanel;
462     }
463
464
465     private void scaleChanged(javax.swing.event.ChangeEvent JavaDoc evt) {
466         setLogarithmic(jRadioButtonScaleLogarithmic.isSelected());
467     }
468
469
470     private void sleepSliderPropertyChange(java.beans.PropertyChangeEvent JavaDoc evt) {
471         if (!sleepSlider.getValueIsAdjusting()) {
472             reschedule();
473         }
474     }
475
476
477     /**
478      * Should be overridden by non-abstract subclasses to provide an observation
479      * of all time series datasets.
480      */

481     public abstract void addObservation() throws Exception JavaDoc;
482
483     private void addObservationHandler() {
484         try {
485             addObservation();
486             if (failures > 0)
487                 failures--;
488         } catch (Exception JavaDoc e) {
489             failures++;
490             org.openide.windows.IOProvider.getDefault().getStdOut().println(e);
491         }
492         if (failures > MAX_FAILURES) {
493             pauseSchedule();
494         }
495
496         updateRange();
497
498     }
499
500     /**
501      *
502      * @param name The attribute name
503      * @param key The key to the value, usually an EmsAttribute
504      */

505     protected void createTimeSeries(String JavaDoc name, T key) {
506         TimeSeries ts = new TimeSeries(name, Millisecond.class);
507         ts.setMaximumItemAge(1000 * 60 * 60 * 48); // 48 hours
508
this.timeSeriesMap.put(key, ts);
509         //ts.setKey((Comparable) key); Duh, don't do this
510
dataset.addSeries(ts);
511     }
512
513     protected TimeSeries getTimeSeries(T key) {
514         return this.timeSeriesMap.get(key);
515     }
516
517     public Set JavaDoc<T> getTimeSeriesKeys() {
518         return this.timeSeriesMap.keySet();
519     }
520
521     /**
522      * The data generator.
523      */

524     protected class DataGenerator extends TimerTask JavaDoc {
525
526         public void run() {
527             addObservationHandler();
528         }
529     }
530
531
532
533     private static class TestGraph extends AbstractGraphPanel {
534         public static final String JavaDoc TEST = "test";
535         private int x = 1;
536         public TestGraph() {
537             createTimeSeries(TEST, TEST);
538             reschedule();
539         }
540         public void addObservation() throws Exception JavaDoc {
541             getTimeSeries(TEST).
542                 add(new Millisecond(), new Integer JavaDoc(x++));
543         }
544     }
545
546     public static void main(String JavaDoc[] args) {
547         TestGraph graph = new TestGraph();
548
549         JFrame frame = new JFrame();
550         JPanel panel = new JPanel();
551         panel.setLayout(new BorderLayout JavaDoc());
552         frame.getContentPane().add(panel);
553         panel.add(graph, BorderLayout.CENTER);
554
555         frame.pack();
556         frame.addWindowListener(new WindowAdapter JavaDoc() {
557             public void windowClosing(WindowEvent JavaDoc e) {
558                 System.exit(0);
559             }
560         });
561         frame.setVisible(true);
562     }
563
564 }
565
Popular Tags