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.cpu;
042:
043: import org.netbeans.lib.profiler.global.CommonConstants;
044: import org.netbeans.lib.profiler.results.CCTNode;
045: import org.netbeans.lib.profiler.results.cpu.CPUResultsSnapshot;
046: import org.netbeans.lib.profiler.results.cpu.PrestimeCPUCCTNode;
047: import org.netbeans.lib.profiler.ui.ResultsPanel;
048: import java.awt.*;
049: import java.awt.event.ActionEvent;
050: import java.awt.event.ActionListener;
051: import java.util.ResourceBundle;
052: import javax.swing.*;
053: import javax.swing.table.TableCellRenderer;
054: import javax.swing.tree.TreePath;
055:
056: /**
057: * Common superclass for all results displays displaying CPU results.
058: *
059: * @author Misha Dmitriev
060: * @author Ian Formanek
061: * @author Jiri Sedlacek
062: */
063: public abstract class CPUResultsPanel extends ResultsPanel implements
064: CommonConstants {
065: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
066:
067: // -----
068: // I18N String constants
069: private static final ResourceBundle messages = ResourceBundle
070: .getBundle("org.netbeans.lib.profiler.ui.cpu.Bundle"); // NOI18N
071: private static final String GO_TO_SOURCE_ITEM_NAME = messages
072: .getString("CPUResultsPanel_GoToSourceItemName"); // NOI18N
073: private static final String BACKTRACES_ITEM_NAME = messages
074: .getString("CPUResultsPanel_BackTracesItemName"); // NOI18N
075: private static final String SUBTREE_ITEM_NAME = messages
076: .getString("CPUResultsPanel_SubtreeItemName"); // NOI18N
077: private static final String ROOT_METHODS_ITEM_NAME = messages
078: .getString("CPUResultsPanel_RootMethodsItemName"); // NOI18N
079: // -----
080:
081: //~ Instance fields ----------------------------------------------------------------------------------------------------------
082:
083: protected CPUResUserActionsHandler actionsHandler;
084: protected JMenuItem popupAddToRoots;
085: protected JMenuItem popupFind;
086: protected JMenuItem popupShowReverse;
087: protected JMenuItem popupShowSource;
088: protected JMenuItem popupShowSubtree;
089: protected JPopupMenu callGraphPopupMenu;
090: protected JPopupMenu cornerPopup;
091: protected TreePath popupPath;
092: protected String[] columnNames;
093: protected TableCellRenderer[] columnRenderers;
094: protected String[] columnToolTips;
095: protected int[] columnWidths;
096: protected boolean[] columnsVisibility;
097: protected int columnCount = 0;
098: protected int currentView; // View AKA aggregation level: CPUResultsSnapshot.METHOD_LEVEL, CLASS_LEVEL or PACKAGE_LEVEL
099: protected int methodId;
100:
101: //~ Constructors -------------------------------------------------------------------------------------------------------------
102:
103: public CPUResultsPanel(CPUResUserActionsHandler actionsHandler) {
104: this .actionsHandler = actionsHandler;
105: callGraphPopupMenu = createPopupMenu();
106:
107: if (popupFind != null) {
108: popupFind.setVisible(false);
109: }
110: }
111:
112: //~ Methods ------------------------------------------------------------------------------------------------------------------
113:
114: /** Returns a meaningful value only for those subclasses that present data for a single thread */
115: public abstract int getCurrentThreadId();
116:
117: public int getCurrentView() {
118: return currentView;
119: }
120:
121: public JMenuItem getPopupFindItem() {
122: return popupFind;
123: }
124:
125: // Should be overriden whenever possible
126: public boolean getSortingOrder() {
127: return false;
128: }
129:
130: /** Changes the aggregation level for the CPU Results
131: *
132: * @param view one of CPUResultsSnapshot.METHOD_LEVEL_VIEW, CPUResultsSnapshot.CLASS_LEVEL_VIEW, CPUResultsSnapshot.PACKAGE_LEVEL_VIEW
133: *
134: * @see CPUResultsSnapshot.METHOD_LEVEL_VIEW
135: * @see CPUResultsSnapshot.CLASS_LEVEL_VIEW
136: * @see CPUResultsSnapshot.PACKAGE_LEVEL_VIEW
137: */
138: public void changeView(int view) {
139: if (currentView == view) {
140: return;
141: }
142:
143: currentView = view;
144:
145: popupShowSource.setEnabled(isShowSourceAvailable());
146: popupAddToRoots.setEnabled(isAddToRootsAvailable());
147:
148: actionsHandler.viewChanged(view); // notify the actions handler about this
149: }
150:
151: public abstract void reset();
152:
153: // Should be overriden whenever possible
154: public int getSortingColumn() {
155: return CommonConstants.SORTING_COLUMN_DEFAULT;
156: }
157:
158: protected boolean isAddToRootsAvailable() {
159: return (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW);
160: }
161:
162: protected abstract String[] getMethodClassNameAndSig(int methodId,
163: int currentView);
164:
165: protected abstract String getSelectedMethodName();
166:
167: protected boolean isShowSourceAvailable() {
168: return (currentView != CPUResultsSnapshot.PACKAGE_LEVEL_VIEW);
169: }
170:
171: // ------------------------------------------------------------------
172: // Popup menu behavior
173: protected JPopupMenu createPopupMenu() {
174: JPopupMenu popup = new JPopupMenu();
175: popupShowSource = new JMenuItem();
176: popupAddToRoots = new JMenuItem();
177: popupFind = new JMenuItem();
178:
179: Font boldfont = popup.getFont().deriveFont(Font.BOLD);
180:
181: ActionListener menuListener = new ActionListener() {
182: public void actionPerformed(ActionEvent evt) {
183: menuActionPerformed(evt);
184: }
185: };
186:
187: popupShowSource.setFont(boldfont);
188: popupShowSource.setText(GO_TO_SOURCE_ITEM_NAME);
189: popup.add(popupShowSource);
190:
191: boolean separator = false;
192:
193: if (supportsSubtreeCallGraph()) {
194: if (!separator) {
195: popup.addSeparator();
196: separator = true;
197: }
198:
199: popupShowSubtree = new JMenuItem();
200: popupShowSubtree.setText(SUBTREE_ITEM_NAME);
201: popup.add(popupShowSubtree);
202: popupShowSubtree.addActionListener(menuListener);
203: }
204:
205: if (supportsReverseCallGraph()) {
206: if (!separator) {
207: popup.addSeparator();
208: separator = true;
209: }
210:
211: popupShowReverse = new JMenuItem();
212: popupShowReverse.setText(BACKTRACES_ITEM_NAME);
213: popup.add(popupShowReverse);
214: popupShowReverse.addActionListener(menuListener);
215: }
216:
217: popup.add(popupFind);
218:
219: popup.addSeparator();
220:
221: popupAddToRoots.setText(ROOT_METHODS_ITEM_NAME);
222: popup.add(popupAddToRoots);
223:
224: popupShowSource.addActionListener(menuListener);
225: popupAddToRoots.addActionListener(menuListener);
226: popupFind.addActionListener(menuListener);
227:
228: return popup;
229: }
230:
231: protected void performDefaultAction() {
232: if (popupPath != null) {
233: showSourceForMethod(popupPath);
234: } else {
235: showSourceForMethod(methodId);
236: }
237: }
238:
239: protected void showSourceForMethod(int methodId) {
240: if (currentView != CPUResultsSnapshot.PACKAGE_LEVEL_VIEW) {
241: boolean methodLevelView = (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW);
242: String[] classMethodAndSig = getMethodClassNameAndSig(
243: methodId, currentView);
244: actionsHandler.showSourceForMethod(classMethodAndSig[0],
245: methodLevelView ? classMethodAndSig[1] : null,
246: methodLevelView ? classMethodAndSig[2] : null);
247: }
248: }
249:
250: protected void showSourceForMethod(TreePath popupPath) {
251: if (currentView != CPUResultsSnapshot.PACKAGE_LEVEL_VIEW) {
252: boolean methodLevelView = (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW);
253: PrestimeCPUCCTNode node = (PrestimeCPUCCTNode) popupPath
254: .getLastPathComponent();
255: String[] classMethodAndSig = getMethodClassNameAndSig(node
256: .getMethodId(), currentView);
257: actionsHandler.showSourceForMethod(classMethodAndSig[0],
258: methodLevelView ? classMethodAndSig[1] : null,
259: methodLevelView ? classMethodAndSig[2] : null);
260: }
261: }
262:
263: protected abstract boolean supportsReverseCallGraph();
264:
265: protected abstract boolean supportsSubtreeCallGraph();
266:
267: protected void showReverseCallGraph(int threadId, int methodId,
268: int currentView, int sortingColumn, boolean sortingOrder) {
269: // do nothing, has to be overriden by classes that do support showing reverse call graphs and return
270: // true from supportsReverseCallGraph
271: }
272:
273: protected void showSubtreeCallGraph(final CCTNode node,
274: int currentView, int sortingColumn, boolean sortingOrder) {
275: // do nothing, has to be overriden by classes that do support showing subtree call graphs and return
276: // true from supportsSubtreeCallGraph
277: }
278:
279: void menuActionPerformed(ActionEvent evt) {
280: Object src = evt.getSource();
281:
282: if (src == popupShowSource) {
283: performDefaultAction();
284: } else if (src == popupShowReverse) {
285: int threadId = 0;
286:
287: if (popupPath != null) {
288: PrestimeCPUCCTNode selectedNode = (PrestimeCPUCCTNode) popupPath
289: .getLastPathComponent();
290:
291: if (selectedNode.getParent() == null) {
292: return; // Nothing to do for root node
293: }
294:
295: if (selectedNode.isSelfTimeNode()) {
296: selectedNode = (PrestimeCPUCCTNode) selectedNode
297: .getParent();
298: }
299:
300: if (selectedNode == null) {
301: return; // Nothing to do for root node
302: }
303:
304: if (selectedNode.getMethodId() == 0) {
305: if (selectedNode.getNChildren() > 0) {
306: methodId = ((PrestimeCPUCCTNode) selectedNode
307: .getChild(0)).getMethodId();
308: }
309: } else {
310: methodId = selectedNode.getMethodId();
311: }
312:
313: threadId = selectedNode.getThreadId();
314: } else {
315: // methodId is already set
316: threadId = getCurrentThreadId(); // It's a flat profile window or something and we request a path for its single thread
317: }
318:
319: showReverseCallGraph(threadId, methodId, currentView,
320: getSortingColumn(), getSortingOrder());
321: } else if (src == popupShowSubtree) {
322: if (popupPath != null) {
323: if (popupPath.getParentPath() == null) {
324: return; // Nothing to do for root node
325: }
326:
327: PrestimeCPUCCTNode selectedNode = (PrestimeCPUCCTNode) popupPath
328: .getLastPathComponent();
329:
330: if (selectedNode.isSelfTimeNode()) {
331: selectedNode = (PrestimeCPUCCTNode) selectedNode
332: .getParent();
333: }
334:
335: if (selectedNode == null) {
336: return; // Nothing to do for root node
337: }
338:
339: showSubtreeCallGraph(selectedNode, currentView,
340: getSortingColumn(), getSortingOrder());
341: }
342: } else if (src == popupAddToRoots) {
343: if (popupPath != null) {
344: PrestimeCPUCCTNode selectedNode = (PrestimeCPUCCTNode) popupPath
345: .getLastPathComponent();
346:
347: if (selectedNode.getMethodId() == 0) {
348: if (selectedNode.getParent() instanceof PrestimeCPUCCTNode) {
349: methodId = ((PrestimeCPUCCTNode) selectedNode
350: .getParent()).getMethodId();
351: }
352: } else {
353: methodId = selectedNode.getMethodId();
354: }
355: } // else methodId is already set
356:
357: String[] methodClassNameAndSig = getMethodClassNameAndSig(
358: methodId, currentView);
359: actionsHandler.addMethodToRoots(methodClassNameAndSig[0],
360: methodClassNameAndSig[1], methodClassNameAndSig[2]);
361: } else if (src == popupFind) {
362: actionsHandler.find(this, getSelectedMethodName());
363: }
364: }
365: }
|