001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.graphs;
042:
043: import org.netbeans.lib.profiler.ui.UIUtils;
044: import org.netbeans.lib.profiler.ui.charts.ChartModelListener;
045: import org.netbeans.lib.profiler.ui.charts.SynchronousXYChart;
046: import org.netbeans.lib.profiler.ui.components.ColorIcon;
047: import org.netbeans.lib.profiler.ui.monitor.SurvivingGenerationsXYChartModel;
048: import org.netbeans.lib.profiler.ui.monitor.VMTelemetryXYChartModel;
049: import org.netbeans.lib.profiler.ui.monitor.VMTelemetryXYChartModelDataResetListener;
050: import java.awt.*;
051: import java.awt.event.InputEvent;
052: import java.awt.event.MouseAdapter;
053: import java.awt.event.MouseEvent;
054: import java.util.ResourceBundle;
055: import javax.swing.*;
056: import javax.swing.border.LineBorder;
057:
058: /**
059: * A panel that contains the graph for surviving generations and time spent in GC.
060: *
061: * @author Vladislav Nemec
062: * @author Ian Formanek
063: * @author Jiri Sedlacek
064: */
065: public class SurvivingGenerationsGraphPanel extends GraphPanel
066: implements ChartModelListener,
067: VMTelemetryXYChartModelDataResetListener {
068: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
069:
070: // -----
071: // I18N String constants
072: private static final ResourceBundle messages = ResourceBundle
073: .getBundle("org.netbeans.lib.profiler.ui.graphs.Bundle"); // NOI18N
074: private static final String SURVGEN_CURRENT_STRING = messages
075: .getString("SurvivingGenerationsGraphPanel_SurvGenCurrentString"); // NOI18N
076: private static final String SURVGEN_MAXIMUM_STRING = messages
077: .getString("SurvivingGenerationsGraphPanel_SurvGenMaximumString"); // NOI18N
078: private static final String GC_TIME_CURRENT_STRING = messages
079: .getString("SurvivingGenerationsGraphPanel_GcTimeCurrentString"); // NOI18N
080: private static final String GC_TIME_MAXIMUM_STRING = messages
081: .getString("SurvivingGenerationsGraphPanel_GcTimeMaximumString"); // NOI18N
082: private static final String TIME_AT_CURSOR_STRING = messages
083: .getString("SurvivingGenerationsGraphPanel_TimeAtCursorString"); // NOI18N
084: private static final String SURVGEN_AT_CURSOR_STRING = messages
085: .getString("SurvivingGenerationsGraphPanel_SurvGenAtCursorString"); // NOI18N
086: private static final String GC_TIME_AT_CURSOR_STRING = messages
087: .getString("SurvivingGenerationsGraphPanel_GcTimeAtCursorString"); // NOI18N
088: private static final String CHART_ACCESS_NAME = messages
089: .getString("SurvivingGenerationsGraphPanel_ChartAccessName"); // NOI18N
090: // -----
091:
092: //~ Instance fields ----------------------------------------------------------------------------------------------------------
093:
094: private JPanel bigLegendPanel;
095: private JPanel smallLegendPanel;
096: private SurvivingGenerationsXYChartModel survivingGenerationsXYChartModel;
097: private SynchronousXYChart xyChart;
098: private boolean completeFunctionality;
099: private int chartTimeLength = 180000; // 3 minutes to switch from fitToWindow to trackingEnd
100:
101: //private int chartTimeLength = 10000; // 10 seconds for testing purposes
102:
103: //~ Constructors -------------------------------------------------------------------------------------------------------------
104:
105: /**
106: * Creates new form SurvivingGenerationsGraphPanel with the default history size (3 minutes)
107: * and no mouse zooming capabilities
108: */
109: public SurvivingGenerationsGraphPanel(
110: final VMTelemetryXYChartModel survivingGenerationsXYChartModel,
111: final Action detailsAction) {
112: this (false, null, survivingGenerationsXYChartModel, null);
113: }
114:
115: /** Creates new form SurvivingGenerationsGraphPanel with the given amount of history to keep
116: *
117: * @param completeFunctionality if true, the chart can be zoomed using mouse and will display all history, if false, it will only display last session and 3 minutes of data
118: * @param backgroundPaint paint used for drawing graph background
119: */
120: public SurvivingGenerationsGraphPanel(
121: final boolean completeFunctionality,
122: final Color backgroundPaint,
123: final VMTelemetryXYChartModel survivingGenerationsXYChartModel,
124: final Action detailsAction) {
125: this .completeFunctionality = completeFunctionality;
126: this .survivingGenerationsXYChartModel = (SurvivingGenerationsXYChartModel) survivingGenerationsXYChartModel;
127:
128: survivingGenerationsXYChartModel.addDataResetListener(this );
129:
130: setLayout(new java.awt.BorderLayout());
131:
132: // --- Big legend panel ----------------------------------------------------
133: JLabel survivingGenerationsLabelBig = new JLabel(
134: survivingGenerationsXYChartModel.getSeriesName(0),
135: new ColorIcon(survivingGenerationsXYChartModel
136: .getSeriesColor(0), Color.BLACK, 18, 9),
137: SwingConstants.LEADING);
138: survivingGenerationsLabelBig.setBorder(BorderFactory
139: .createEmptyBorder(0, 5, 0, 0));
140:
141: JLabel relativeTimeGCBig = new JLabel(
142: survivingGenerationsXYChartModel.getSeriesName(1),
143: new ColorIcon(survivingGenerationsXYChartModel
144: .getSeriesColor(1), Color.BLACK, 18, 9),
145: SwingConstants.LEADING);
146: relativeTimeGCBig.setBorder(BorderFactory.createEmptyBorder(0,
147: 5, 0, 0));
148:
149: bigLegendPanel = new JPanel();
150: bigLegendPanel.add(survivingGenerationsLabelBig);
151: bigLegendPanel.add(relativeTimeGCBig);
152:
153: // --- Small legend panel --------------------------------------------------
154: JLabel survivingGenerationsLabelSmall = new JLabel(
155: survivingGenerationsXYChartModel.getSeriesName(0),
156: new ColorIcon(survivingGenerationsXYChartModel
157: .getSeriesColor(0), null, 8, 8),
158: SwingConstants.LEADING);
159: survivingGenerationsLabelSmall.setFont(getFont().deriveFont(
160: (float) (getFont().getSize()) - 1));
161: survivingGenerationsLabelSmall.setBorder(BorderFactory
162: .createEmptyBorder(0, 5, 0, 5));
163:
164: JLabel relativeTimeGCSmall = new JLabel(
165: survivingGenerationsXYChartModel.getSeriesName(1),
166: new ColorIcon(survivingGenerationsXYChartModel
167: .getSeriesColor(1), null, 8, 8),
168: SwingConstants.LEADING);
169: relativeTimeGCSmall.setFont(getFont().deriveFont(
170: (float) (getFont().getSize()) - 1));
171: relativeTimeGCSmall.setBorder(BorderFactory.createEmptyBorder(
172: 0, 5, 0, 5));
173:
174: smallLegendPanel = new JPanel();
175: smallLegendPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0,
176: 1));
177: smallLegendPanel.setBackground(Color.WHITE);
178: smallLegendPanel.setBorder(new LineBorder(new Color(235, 235,
179: 235), 1));
180: smallLegendPanel.add(survivingGenerationsLabelSmall);
181: smallLegendPanel.add(relativeTimeGCSmall);
182:
183: // --- Chart panel ---------------------------------------------------------
184: xyChart = new SynchronousXYChart(SynchronousXYChart.TYPE_LINE,
185: SynchronousXYChart.VALUES_INTERPOLATED, 0.01) {
186: public String getToolTipText(MouseEvent event) {
187: return getChartToolTipText(event);
188: }
189: };
190:
191: xyChart.setUseSecondaryVerticalAxis(true);
192:
193: long time = System.currentTimeMillis();
194: xyChart.setupInitialAppearance(time, time + 1200, 0, 2);
195: getAccessibleContext().setAccessibleName(CHART_ACCESS_NAME);
196: xyChart.setAccessibleContext(getAccessibleContext());
197:
198: if (completeFunctionality) {
199: xyChart.setTopChartMargin(50);
200: xyChart.allowSelection();
201: xyChart.setMinimumVerticalMarksDistance(50);
202: } else {
203: xyChart.setTopChartMargin(20);
204: xyChart.denySelection();
205: xyChart.setMinimumVerticalMarksDistance(UIManager.getFont(
206: "Panel.font").getSize() + 8); // NOI18N
207: }
208:
209: xyChart.setVerticalAxisValueDivider2(10);
210: xyChart.setVerticalAxisValueString2("%"); // NOI18N
211:
212: chartDataReset();
213:
214: if (backgroundPaint != null) {
215: setOpaque(true);
216: setBackground(backgroundPaint);
217: xyChart.setBackgroundPaint(backgroundPaint);
218: }
219:
220: xyChart.setModel(survivingGenerationsXYChartModel);
221:
222: if (!completeFunctionality) {
223: survivingGenerationsXYChartModel
224: .addChartModelListener(this ); // Needs to be AFTER xyChart.setModel() !!!
225: }
226:
227: add(xyChart);
228:
229: xyChart.addMouseListener(new MouseAdapter() {
230: public void mouseClicked(MouseEvent e) {
231: if ((e.getModifiers() == InputEvent.BUTTON1_MASK)
232: && (e.getClickCount() == 2)) {
233: if (detailsAction != null) {
234: detailsAction.actionPerformed(null);
235: }
236: }
237: }
238: });
239:
240: ToolTipManager.sharedInstance().registerComponent(xyChart);
241: }
242:
243: //~ Methods ------------------------------------------------------------------------------------------------------------------
244:
245: public JPanel getBigLegendPanel() {
246: return bigLegendPanel;
247: }
248:
249: // ----------------------------------------------------------------------------
250: // Public API
251: public SynchronousXYChart getChart() {
252: return xyChart;
253: }
254:
255: public String getChartToolTipText(MouseEvent event) {
256: if (survivingGenerationsXYChartModel.getItemCount() < 2) {
257: return null;
258: }
259:
260: StringBuffer toolTipBuffer = new StringBuffer();
261:
262: toolTipBuffer.append("<html>"); // NOI18N
263:
264: if (!completeFunctionality
265: || !xyChart.hasValidDataForPosition(event.getX(), event
266: .getY())) {
267: appendToolTipItem(toolTipBuffer, SURVGEN_CURRENT_STRING,
268: intFormat.format(survivingGenerationsXYChartModel
269: .getYValue(survivingGenerationsXYChartModel
270: .getItemCount() - 1, 0)), false);
271: appendToolTipItem(toolTipBuffer, SURVGEN_MAXIMUM_STRING,
272: intFormat.format(survivingGenerationsXYChartModel
273: .getMaxYValue(0)), false);
274: appendToolTipItem(
275: toolTipBuffer,
276: GC_TIME_CURRENT_STRING,
277: percentFormat
278: .format(survivingGenerationsXYChartModel
279: .getYValue(
280: survivingGenerationsXYChartModel
281: .getItemCount() - 1,
282: 1) / 1000f), false);
283: appendToolTipItem(toolTipBuffer, GC_TIME_MAXIMUM_STRING,
284: percentFormat
285: .format(survivingGenerationsXYChartModel
286: .getMaxYValue(1) / 1000f), true);
287: } else {
288: appendToolTipItem(toolTipBuffer, SURVGEN_CURRENT_STRING,
289: intFormat.format(survivingGenerationsXYChartModel
290: .getYValue(survivingGenerationsXYChartModel
291: .getItemCount() - 1, 0)), false);
292: appendToolTipItem(toolTipBuffer, SURVGEN_MAXIMUM_STRING,
293: intFormat.format(survivingGenerationsXYChartModel
294: .getMaxYValue(0)), false);
295: appendToolTipItem(
296: toolTipBuffer,
297: GC_TIME_CURRENT_STRING,
298: percentFormat
299: .format(survivingGenerationsXYChartModel
300: .getYValue(
301: survivingGenerationsXYChartModel
302: .getItemCount() - 1,
303: 1) / 1000f), false);
304: appendToolTipItem(toolTipBuffer, GC_TIME_MAXIMUM_STRING,
305: percentFormat
306: .format(survivingGenerationsXYChartModel
307: .getMaxYValue(1) / 1000f), false);
308:
309: toolTipBuffer.append("<br>"); // NOI18N
310:
311: appendToolTipItem(toolTipBuffer, TIME_AT_CURSOR_STRING,
312: xyChart.getTimeAtPosition(event.getX()), false);
313: appendToolTipItem(toolTipBuffer, SURVGEN_AT_CURSOR_STRING,
314: intFormat.format(xyChart.getYValueAtPosition(event
315: .getX(), 0)), false);
316: appendToolTipItem(toolTipBuffer, GC_TIME_AT_CURSOR_STRING,
317: percentFormat.format(xyChart.getYValueAtPosition(
318: event.getX(), 1) / 1000f), true);
319: }
320:
321: toolTipBuffer.append("</html>"); // NOI18N
322:
323: return toolTipBuffer.toString();
324: }
325:
326: public JPanel getSmallLegendPanel() {
327: return smallLegendPanel;
328: }
329:
330: // --- ChartModelListener ----------------------------------------------------
331: public void chartDataChanged() {
332: if (!completeFunctionality) {
333: if (xyChart.isFitToWindow()
334: && ((survivingGenerationsXYChartModel
335: .getMaxXValue() - survivingGenerationsXYChartModel
336: .getMinXValue()) >= chartTimeLength)) { // after 3 minutes switch from fitToWindow to trackingEnd
337: UIUtils.runInEventDispatchThread(new Runnable() {
338: public void run() {
339: xyChart.setTrackingEnd();
340: }
341: });
342: }
343: }
344: }
345:
346: // --- VMTelemetryXYChartModelDataResetListener ------------------------------
347: public void chartDataReset() {
348: UIUtils.runInEventDispatchThread(new Runnable() {
349: public void run() {
350: xyChart.resetChart();
351:
352: if (completeFunctionality) {
353: //xyChart.setScale(0.01);
354: //xyChart.setViewOffsetX(0);
355: xyChart.resetTrackingEnd();
356: xyChart.resetFitToWindow();
357: } else {
358: xyChart.setFitToWindow();
359: }
360: }
361: });
362: }
363:
364: // --- ToolTip stuff ---------------------------------------------------------
365: private static void appendToolTipItem(StringBuffer toolTipBuffer,
366: String itemName, String itemValue, boolean lastItem) {
367: toolTipBuffer.append(" <b>"); // NOI18N
368: toolTipBuffer.append(itemName);
369: toolTipBuffer.append("</b>: "); // NOI18N
370: toolTipBuffer.append(itemValue);
371: toolTipBuffer.append(" "); // NOI18N
372:
373: if (!lastItem) {
374: toolTipBuffer.append("<br>"); // NOI18N
375: }
376: }
377: }
|