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.VMTelemetryXYChartModel;
048: import org.netbeans.lib.profiler.ui.monitor.VMTelemetryXYChartModelDataResetListener;
049: import java.awt.*;
050: import java.awt.event.InputEvent;
051: import java.awt.event.MouseAdapter;
052: import java.awt.event.MouseEvent;
053: import java.util.ResourceBundle;
054: import javax.swing.*;
055: import javax.swing.border.LineBorder;
056:
057: /**
058: * A panel with heap graph display.
059: *
060: * @author Vladislav Nemec
061: * @author Ian Formanek
062: * @author Jiri Sedlacek
063: */
064: public class MemoryGraphPanel extends GraphPanel implements
065: ChartModelListener, VMTelemetryXYChartModelDataResetListener {
066: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
067:
068: // -----
069: // I18N String constants
070: private static final ResourceBundle messages = ResourceBundle
071: .getBundle("org.netbeans.lib.profiler.ui.graphs.Bundle"); // NOI18N
072: private static final String TOTAL_MEMORY_CURRENT_STRING = messages
073: .getString("MemoryGraphPanel_TotalMemoryCurrentString"); // NOI18N
074: private static final String USED_MEMORY_CURRENT_STRING = messages
075: .getString("MemoryGraphPanel_UsedMemoryCurrentString"); // NOI18N
076: private static final String USED_MEMORY_MAXIMUM_STRING = messages
077: .getString("MemoryGraphPanel_UsedMemoryMaximumString"); // NOI18N
078: private static final String TIME_AT_CURSOR_STRING = messages
079: .getString("MemoryGraphPanel_TimeAtCursorString"); // NOI18N
080: private static final String TOTAL_MEMORY_AT_CURSOR_STRING = messages
081: .getString("MemoryGraphPanel_TotalMemoryAtCursorString"); // NOI18N
082: private static final String USED_MEMORY_AT_CURSOR_STRING = messages
083: .getString("MemoryGraphPanel_UsedMemoryAtCursorString"); // NOI18N
084: private static final String CHART_ACCESS_NAME = messages
085: .getString("MemoryGraphPanel_ChartAccessName"); // NOI18N
086: // -----
087:
088: //~ Instance fields ----------------------------------------------------------------------------------------------------------
089:
090: private JPanel bigLegendPanel;
091: private JPanel smallLegendPanel;
092: private SynchronousXYChart xyChart;
093: private VMTelemetryXYChartModel memoryXYChartModel;
094: private boolean completeFunctionality;
095: private int chartTimeLength = 180000; // 3 minutes to switch from fitToWindow to trackingEnd
096:
097: //private int chartTimeLength = 10000; // 10 seconds for testing purposes
098:
099: //~ Constructors -------------------------------------------------------------------------------------------------------------
100:
101: /** Creates new form MemoryGraphPanel with the default history size (3 minutes)
102: * and no mouse zooming capabilities
103: * @param telemetryManager The data manager for telemetry data
104: */
105: public MemoryGraphPanel(
106: final VMTelemetryXYChartModel memoryXYChartModel,
107: final Action detailsAction) {
108: this (false, null, memoryXYChartModel, detailsAction);
109: }
110:
111: /** Creates new form MemoryGraphPanel with the given amount of history to keep
112: *
113: * @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
114: * @param backgroundPaint paint used for drawing graph background
115: * @param telemetryManager The data manager for telemetry data
116: */
117: public MemoryGraphPanel(final boolean completeFunctionality,
118: final Color backgroundPaint,
119: final VMTelemetryXYChartModel memoryXYChartModel,
120: final Action detailsAction) {
121: this .completeFunctionality = completeFunctionality;
122: this .memoryXYChartModel = memoryXYChartModel;
123:
124: memoryXYChartModel.addDataResetListener(this );
125:
126: setLayout(new java.awt.BorderLayout());
127:
128: // --- Big legend panel ----------------------------------------------------
129: JLabel heapSizeBig = new JLabel(memoryXYChartModel
130: .getSeriesName(0), new ColorIcon(memoryXYChartModel
131: .getSeriesColor(0), Color.BLACK, 18, 9),
132: SwingConstants.LEADING);
133: heapSizeBig.setBorder(BorderFactory.createEmptyBorder(0, 5, 0,
134: 0));
135:
136: JLabel usedHeapBig = new JLabel(memoryXYChartModel
137: .getSeriesName(1), new ColorIcon(memoryXYChartModel
138: .getSeriesColor(1), Color.BLACK, 18, 9),
139: SwingConstants.LEADING);
140: usedHeapBig.setBorder(BorderFactory.createEmptyBorder(0, 5, 0,
141: 0));
142:
143: bigLegendPanel = new JPanel();
144: bigLegendPanel.add(heapSizeBig);
145: bigLegendPanel.add(usedHeapBig);
146:
147: // --- Small legend panel --------------------------------------------------
148: JLabel heapSizeSmall = new JLabel(memoryXYChartModel
149: .getSeriesName(0), new ColorIcon(memoryXYChartModel
150: .getSeriesColor(0), null, 8, 8), SwingConstants.LEADING);
151: heapSizeSmall.setFont(getFont().deriveFont(
152: (float) (getFont().getSize()) - 1));
153: heapSizeSmall.setBorder(BorderFactory.createEmptyBorder(0, 5,
154: 0, 5));
155:
156: JLabel usedHeapSmall = new JLabel(memoryXYChartModel
157: .getSeriesName(1), new ColorIcon(memoryXYChartModel
158: .getSeriesColor(1), null, 8, 8), SwingConstants.LEADING);
159: usedHeapSmall.setFont(getFont().deriveFont(
160: (float) (getFont().getSize()) - 1));
161: usedHeapSmall.setBorder(BorderFactory.createEmptyBorder(0, 5,
162: 0, 5));
163:
164: smallLegendPanel = new JPanel();
165: smallLegendPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0,
166: 1));
167: smallLegendPanel.setBackground(Color.WHITE);
168: smallLegendPanel.setBorder(new LineBorder(new Color(235, 235,
169: 235), 1));
170: smallLegendPanel.add(heapSizeSmall);
171: smallLegendPanel.add(usedHeapSmall);
172:
173: // --- Chart panel ---------------------------------------------------------
174: xyChart = new SynchronousXYChart(SynchronousXYChart.TYPE_FILL,
175: SynchronousXYChart.VALUES_INTERPOLATED, 0.01) {
176: public String getToolTipText(MouseEvent event) {
177: return getChartToolTipText(event);
178: }
179: };
180:
181: if (completeFunctionality) {
182: xyChart.setTopChartMargin(50);
183: xyChart.allowSelection();
184: xyChart.setMinimumVerticalMarksDistance(50);
185: } else {
186: xyChart.setTopChartMargin(20);
187: xyChart.denySelection();
188: xyChart.setMinimumVerticalMarksDistance(UIManager.getFont(
189: "Panel.font").getSize() + 8); // NOI18N
190: }
191:
192: xyChart.setVerticalAxisValueDivider(1024 * 1024);
193: xyChart.setVerticalAxisValueString("M"); // NOI18N
194:
195: long time = System.currentTimeMillis();
196: xyChart.setupInitialAppearance(time, time + 1200, 0, 2);
197: getAccessibleContext().setAccessibleName(CHART_ACCESS_NAME);
198: xyChart.setAccessibleContext(getAccessibleContext());
199:
200: chartDataReset();
201:
202: if (backgroundPaint != null) {
203: setOpaque(true);
204: setBackground(backgroundPaint);
205: xyChart.setBackgroundPaint(backgroundPaint);
206: }
207:
208: xyChart.setModel(memoryXYChartModel);
209:
210: if (!completeFunctionality) {
211: memoryXYChartModel.addChartModelListener(this ); // Needs to be AFTER xyChart.setModel() !!!
212: }
213:
214: add(xyChart);
215:
216: xyChart.addMouseListener(new MouseAdapter() {
217: public void mouseClicked(MouseEvent e) {
218: if ((e.getModifiers() == InputEvent.BUTTON1_MASK)
219: && (e.getClickCount() == 2)) {
220: if (detailsAction != null) {
221: detailsAction.actionPerformed(null);
222: }
223: }
224: }
225: });
226:
227: ToolTipManager.sharedInstance().registerComponent(xyChart);
228: }
229:
230: //~ Methods ------------------------------------------------------------------------------------------------------------------
231:
232: public JPanel getBigLegendPanel() {
233: return bigLegendPanel;
234: }
235:
236: // ------------------------------------------------------------------------------------------
237: // Public API
238: public SynchronousXYChart getChart() {
239: return xyChart;
240: }
241:
242: public String getChartToolTipText(MouseEvent event) {
243: if (memoryXYChartModel.getItemCount() < 2) {
244: return null;
245: }
246:
247: StringBuffer toolTipBuffer = new StringBuffer();
248:
249: toolTipBuffer.append("<html>"); // NOI18N
250:
251: if (!completeFunctionality
252: || !xyChart.hasValidDataForPosition(event.getX(), event
253: .getY())) {
254: appendToolTipItem(toolTipBuffer,
255: TOTAL_MEMORY_CURRENT_STRING, intFormat
256: .format(memoryXYChartModel
257: .getYValue(memoryXYChartModel
258: .getItemCount() - 1, 0))
259: + " B", false); // NOI18N
260: appendToolTipItem(toolTipBuffer,
261: USED_MEMORY_CURRENT_STRING, intFormat
262: .format(memoryXYChartModel
263: .getYValue(memoryXYChartModel
264: .getItemCount() - 1, 1))
265: + " B", false); // NOI18N
266: appendToolTipItem(toolTipBuffer,
267: USED_MEMORY_MAXIMUM_STRING, intFormat
268: .format(memoryXYChartModel.getMaxYValue(1))
269: + " B", true); // NOI18N
270: } else {
271: appendToolTipItem(toolTipBuffer,
272: TOTAL_MEMORY_CURRENT_STRING, intFormat
273: .format(memoryXYChartModel
274: .getYValue(memoryXYChartModel
275: .getItemCount() - 1, 0))
276: + " B", false); // NOI18N
277: appendToolTipItem(toolTipBuffer,
278: USED_MEMORY_CURRENT_STRING, intFormat
279: .format(memoryXYChartModel
280: .getYValue(memoryXYChartModel
281: .getItemCount() - 1, 1))
282: + " B", false); // NOI18N
283: appendToolTipItem(toolTipBuffer,
284: USED_MEMORY_MAXIMUM_STRING, intFormat
285: .format(memoryXYChartModel.getMaxYValue(1))
286: + " B", false); // NOI18N
287:
288: toolTipBuffer.append("<br>"); // NOI18N
289:
290: appendToolTipItem(toolTipBuffer, TIME_AT_CURSOR_STRING,
291: xyChart.getTimeAtPosition(event.getX()), false);
292: appendToolTipItem(toolTipBuffer,
293: TOTAL_MEMORY_AT_CURSOR_STRING, intFormat
294: .format(xyChart.getYValueAtPosition(event
295: .getX(), 0))
296: + " B", false); // NOI18N
297: appendToolTipItem(toolTipBuffer,
298: USED_MEMORY_AT_CURSOR_STRING, intFormat
299: .format(xyChart.getYValueAtPosition(event
300: .getX(), 1))
301: + " B", true); // NOI18N
302: }
303:
304: toolTipBuffer.append("</html>"); // NOI18N
305:
306: return toolTipBuffer.toString();
307: }
308:
309: public JPanel getSmallLegendPanel() {
310: return smallLegendPanel;
311: }
312:
313: // --- ChartModelListener ----------------------------------------------------
314: public void chartDataChanged() {
315: if (!completeFunctionality) {
316: if (xyChart.isFitToWindow()
317: && ((memoryXYChartModel.getMaxXValue() - memoryXYChartModel
318: .getMinXValue()) >= chartTimeLength)) { // after 3 minutes switch from fitToWindow to trackingEnd
319: UIUtils.runInEventDispatchThread(new Runnable() {
320: public void run() {
321: xyChart.setTrackingEnd();
322: }
323: });
324: }
325: }
326: }
327:
328: // --- VMTelemetryXYChartModelDataResetListener ------------------------------
329: public void chartDataReset() {
330: UIUtils.runInEventDispatchThread(new Runnable() {
331: public void run() {
332: xyChart.resetChart();
333:
334: if (completeFunctionality) {
335: //xyChart.setScale(0.01);
336: //xyChart.setViewOffsetX(0);
337: xyChart.resetTrackingEnd();
338: xyChart.resetFitToWindow();
339: } else {
340: xyChart.setFitToWindow();
341: }
342: }
343: });
344: }
345:
346: // --- ToolTip stuff ---------------------------------------------------------
347: private static void appendToolTipItem(StringBuffer toolTipBuffer,
348: String itemName, String itemValue, boolean lastItem) {
349: toolTipBuffer.append(" <b>"); // NOI18N
350: toolTipBuffer.append(itemName);
351: toolTipBuffer.append("</b>: "); // NOI18N
352: toolTipBuffer.append(itemValue);
353: toolTipBuffer.append(" "); // NOI18N
354:
355: if (!lastItem) {
356: toolTipBuffer.append("<br>"); // NOI18N
357: }
358: }
359: }
|