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.modules.profiler;
042:
043: import org.netbeans.lib.profiler.global.CommonConstants;
044: import org.netbeans.modules.profiler.ui.ProfilerDialogs;
045: import org.openide.DialogDescriptor;
046: import org.openide.actions.FindAction;
047: import org.openide.cookies.SaveCookie;
048: import org.openide.nodes.AbstractNode;
049: import org.openide.nodes.Children;
050: import org.openide.nodes.Node;
051: import org.openide.util.NbBundle;
052: import org.openide.util.Utilities;
053: import org.openide.util.actions.CallbackSystemAction;
054: import org.openide.util.actions.SystemAction;
055: import org.openide.windows.TopComponent;
056: import java.awt.*;
057: import java.awt.event.ActionEvent;
058: import java.io.IOException;
059: import java.util.Collection;
060: import java.util.HashMap;
061: import javax.swing.*;
062:
063: /**
064: * An IDE TopComponent to display a snapshot of profiling results.
065: *
066: * @author Tomas Hurka
067: * @author Ian Formanek
068: */
069: public final class SnapshotResultsWindow extends TopComponent implements
070: SnapshotsListener {
071: //~ Inner Interfaces ---------------------------------------------------------------------------------------------------------
072:
073: public static interface FindPerformer {
074: //~ Methods --------------------------------------------------------------------------------------------------------------
075:
076: public void performFind();
077:
078: public void performFindNext();
079:
080: public void performFindPrevious();
081: }
082:
083: //~ Inner Classes ------------------------------------------------------------------------------------------------------------
084:
085: private class SaveNode extends AbstractNode {
086: //~ Constructors ---------------------------------------------------------------------------------------------------------
087:
088: /**
089: * Create a new abstract node with a given child set.
090: */
091: public SaveNode() {
092: super (Children.LEAF);
093: }
094:
095: //~ Methods --------------------------------------------------------------------------------------------------------------
096:
097: public void setSaveEnabled(boolean saveEnabled) {
098: if (saveEnabled) {
099: if (getCookie(SaveCookie.class) == null) {
100: getCookieSet().add(savePerformer);
101: }
102: } else {
103: if (getCookie(SaveCookie.class) != null) {
104: getCookieSet().remove(savePerformer);
105: }
106: }
107: }
108: }
109:
110: private class SavePerformer implements SaveCookie {
111: //~ Methods --------------------------------------------------------------------------------------------------------------
112:
113: public void save() throws IOException {
114: ResultsManager.getDefault().saveSnapshot(snapshot);
115: }
116: }
117:
118: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
119:
120: // -----
121: // I18N String constants
122: private static final String SAVE_SNAPSHOT_DIALOG_MSG = NbBundle
123: .getMessage(SnapshotResultsWindow.class,
124: "SnapshotResultsWindow_SaveSnapshotDialogMsg"); // NOI18N
125: private static final String CPU_SNAPSHOT_ACCESS_DESCR = NbBundle
126: .getMessage(SnapshotResultsWindow.class,
127: "SnapshotResultsWindow_CpuSnapshotAccessDescr"); // NOI18N
128: private static final String FRAGMENT_SNAPSHOT_ACCESS_DESCR = NbBundle
129: .getMessage(SnapshotResultsWindow.class,
130: "SnapshotResultsWindow_FragmentSnapshotAccessDescr"); // NOI18N
131: private static final String MEMORY_SNAPSHOT_ACCESS_DESCR = NbBundle
132: .getMessage(SnapshotResultsWindow.class,
133: "SnapshotResultsWindow_MemorySnapshotAccessDescr"); // NOI18N
134: // -----
135: private static final Image WINDOW_ICON_CPU = Utilities
136: .loadImage("org/netbeans/modules/profiler/resources/cpu.png"); // NOI18N
137: private static final Image WINDOWS_ICON_FRAGMENT = Utilities
138: .loadImage("org/netbeans/modules/profiler/resources/fragment.png"); // NOI18N
139: private static final Image WINDOWS_ICON_MEMORY = Utilities
140: .loadImage("org/netbeans/modules/profiler/resources/memory.png"); // NOI18N
141: private static final HashMap /*<ResultsSnapshot, SnapshotResultsWindow>*/windowsList = new HashMap();
142:
143: //~ Instance fields ----------------------------------------------------------------------------------------------------------
144:
145: private Component lastFocusOwner;
146: private LoadedSnapshot snapshot;
147: private SaveNode saveSupport = new SaveNode();
148: private SavePerformer savePerformer = new SavePerformer();
149: private SnapshotPanel displayedPanel;
150: private String tabName = ""; // NOI18N // default
151: private boolean forcedClose = false;
152:
153: //~ Constructors -------------------------------------------------------------------------------------------------------------
154:
155: /**
156: * This constructor cannot be called, instances of this window cannot be persisted.
157: */
158: public SnapshotResultsWindow() {
159: throw new InternalError(
160: "This constructor should never be called");
161: } // NOI18N
162:
163: /**
164: * Creates a new SnapshotResultsWindow for provided snapshot. The content of this window will vary depending on
165: * the type of snapshot provided.
166: *
167: * @param ls The results snapshot to display
168: */
169: public SnapshotResultsWindow(LoadedSnapshot ls, int sortingColumn,
170: boolean sortingOrder) {
171: this .snapshot = ls;
172: ResultsManager.getDefault().addSnapshotsListener(this );
173: updateSaveState();
174:
175: setLayout(new BorderLayout());
176: setFocusable(true);
177: setRequestFocusEnabled(true);
178:
179: switch (ls.getType()) {
180: case LoadedSnapshot.SNAPSHOT_TYPE_CPU:
181: getAccessibleContext().setAccessibleDescription(
182: CPU_SNAPSHOT_ACCESS_DESCR);
183: displayCPUResults(ls, sortingColumn, sortingOrder);
184:
185: break;
186: case LoadedSnapshot.SNAPSHOT_TYPE_CODEFRAGMENT:
187: getAccessibleContext().setAccessibleDescription(
188: FRAGMENT_SNAPSHOT_ACCESS_DESCR);
189: displayCodeRegionResults(ls);
190:
191: break;
192: case LoadedSnapshot.SNAPSHOT_TYPE_MEMORY_ALLOCATIONS:
193: case LoadedSnapshot.SNAPSHOT_TYPE_MEMORY_LIVENESS:
194: getAccessibleContext().setAccessibleDescription(
195: MEMORY_SNAPSHOT_ACCESS_DESCR);
196: displayMemoryResults(ls, sortingColumn, sortingOrder);
197:
198: break;
199: }
200: }
201:
202: //~ Methods ------------------------------------------------------------------------------------------------------------------
203:
204: public static synchronized void closeAllWindows() {
205: Collection windows = windowsList.values();
206:
207: if (!windows.isEmpty()) {
208: SnapshotResultsWindow[] toClose = new SnapshotResultsWindow[windows
209: .size()];
210: windows.toArray(toClose);
211:
212: for (int i = 0; i < toClose.length; i++) {
213: SnapshotResultsWindow snapshotResultsWindow = toClose[i];
214: snapshotResultsWindow.forcedClose();
215: }
216: }
217: }
218:
219: public static synchronized void closeWindow(LoadedSnapshot snapshot) {
220: SnapshotResultsWindow win = (SnapshotResultsWindow) windowsList
221: .get(snapshot);
222:
223: if (win != null) {
224: win.forcedClose();
225: }
226: }
227:
228: public static synchronized SnapshotResultsWindow get(
229: LoadedSnapshot ls) {
230: // target component decides which column will be used for sorting
231: return SnapshotResultsWindow.get(ls,
232: CommonConstants.SORTING_COLUMN_DEFAULT, false);
233: }
234:
235: public static synchronized SnapshotResultsWindow get(
236: LoadedSnapshot ls, int sortingColumn, boolean sortingOrder) {
237: SnapshotResultsWindow win = (SnapshotResultsWindow) windowsList
238: .get(ls);
239:
240: if (win == null) {
241: win = new SnapshotResultsWindow(ls, sortingColumn,
242: sortingOrder);
243: windowsList.put(ls, win);
244: }
245:
246: return win;
247: }
248:
249: public static synchronized boolean hasSnapshotWindow(
250: LoadedSnapshot ls) {
251: return windowsList.get(ls) != null;
252: }
253:
254: public int getPersistenceType() {
255: return TopComponent.PERSISTENCE_NEVER;
256: }
257:
258: public boolean canClose() {
259: if (forcedClose) {
260: // clean up to avoid being held in memory
261: setActivatedNodes(new Node[0]);
262:
263: return true;
264: }
265:
266: if (snapshot.isSaved()) {
267: return true; // already saved
268: }
269:
270: ProfilerDialogs.DNSAConfirmation dd = new ProfilerDialogs.DNSAConfirmation(
271: "org.netbeans.modules.profiler.SnapshotResultsWindow.canClose", // NOI18N
272: SAVE_SNAPSHOT_DIALOG_MSG,
273: DialogDescriptor.YES_NO_CANCEL_OPTION);
274: dd.setDNSADefault(false);
275:
276: Object ret = ProfilerDialogs.notify(dd);
277:
278: if (ret.equals(DialogDescriptor.CANCEL_OPTION)
279: || ret.equals(DialogDescriptor.CLOSED_OPTION)) {
280: return false;
281: } else if (ret.equals(DialogDescriptor.YES_OPTION)) {
282: ResultsManager.getDefault().saveSnapshot(snapshot);
283: // clean up to avoid being held in memory
284: setActivatedNodes(new Node[0]);
285:
286: return true;
287: } else {
288: // clean up to avoid being held in memory
289: setActivatedNodes(new Node[0]);
290:
291: return true;
292: }
293: }
294:
295: public void componentActivated() {
296: if (lastFocusOwner != null) {
297: lastFocusOwner.requestFocus();
298: } else if (displayedPanel != null) {
299: displayedPanel.requestFocus();
300: }
301: }
302:
303: public void componentDeactivated() {
304: lastFocusOwner = KeyboardFocusManager
305: .getCurrentKeyboardFocusManager().getFocusOwner();
306: }
307:
308: public void displayStacksForClass(int selectedClassId,
309: int sortingColumn, boolean sortingOrder) {
310: if (displayedPanel instanceof MemorySnapshotPanel) {
311: ((MemorySnapshotPanel) displayedPanel)
312: .displayStacksForClass(selectedClassId,
313: sortingColumn, sortingOrder);
314: }
315: }
316:
317: public void snapshotLoaded(LoadedSnapshot snapshot) {
318: // ignore
319: }
320:
321: public void snapshotRemoved(LoadedSnapshot snapshot) {
322: // ignore
323: }
324:
325: public void snapshotSaved(LoadedSnapshot snapshot) {
326: updateSaveState();
327: }
328:
329: public void snapshotTaken(LoadedSnapshot snapshot) {
330: // ignore
331: }
332:
333: public void updateTitle() {
334: if (snapshot.isSaved()) {
335: setName(tabName);
336: } else {
337: setName(tabName + " *"); // NOI18N
338: }
339: }
340:
341: protected void componentClosed() {
342: synchronized (SnapshotResultsWindow.class) {
343: windowsList.remove(snapshot);
344: }
345:
346: ResultsManager.getDefault().closeSnapshot(snapshot);
347: ResultsManager.getDefault().removeSnapshotsListener(this );
348: snapshot = null;
349: }
350:
351: protected String preferredID() {
352: return this .getClass().getName();
353: }
354:
355: // -- Private methods --------------------------------------------------------------------------------------------------
356: private void setTabName(String innerName) {
357: tabName = innerName;
358: updateTitle();
359: }
360:
361: private void displayCPUResults(LoadedSnapshot ls,
362: int sortingColumn, boolean sortingOrder) {
363: CPUSnapshotPanel cpuPanel = new CPUSnapshotPanel(ls,
364: sortingColumn, sortingOrder);
365: displayedPanel = cpuPanel;
366: updateFind(true, cpuPanel);
367: add(cpuPanel, BorderLayout.CENTER);
368: setTabName(cpuPanel.getTitle());
369: setIcon(WINDOW_ICON_CPU);
370: }
371:
372: private void displayCodeRegionResults(LoadedSnapshot ls) {
373: updateFind(false, null);
374:
375: FragmentSnapshotPanel codeRegionPanel = new FragmentSnapshotPanel(
376: ls);
377: displayedPanel = codeRegionPanel;
378: add(codeRegionPanel, BorderLayout.CENTER);
379: setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
380: setTabName(codeRegionPanel.getTitle());
381: setIcon(WINDOWS_ICON_FRAGMENT);
382: }
383:
384: private void displayMemoryResults(LoadedSnapshot ls,
385: int sortingColumn, boolean sortingOrder) {
386: MemorySnapshotPanel memoryPanel = new MemorySnapshotPanel(ls,
387: sortingColumn, sortingOrder);
388: displayedPanel = memoryPanel;
389: updateFind(true, memoryPanel);
390: add(memoryPanel, BorderLayout.CENTER);
391: setTabName(memoryPanel.getTitle());
392: setIcon(WINDOWS_ICON_MEMORY);
393: }
394:
395: private void forcedClose() {
396: forcedClose = true;
397: close();
398: }
399:
400: private void updateFind(boolean enabled,
401: final FindPerformer performer) {
402: CallbackSystemAction globalFindAction = (CallbackSystemAction) SystemAction
403: .get(FindAction.class);
404: Object findActionKey = globalFindAction.getActionMapKey();
405:
406: if (enabled) {
407: getActionMap().put(findActionKey, new AbstractAction() {
408: public void actionPerformed(ActionEvent e) {
409: performer.performFind();
410: }
411: });
412: } else {
413: getActionMap().remove(findActionKey);
414: }
415: }
416:
417: private void updateSaveState() {
418: saveSupport.setSaveEnabled(!snapshot.isSaved());
419: setActivatedNodes(new Node[] { saveSupport });
420:
421: if (displayedPanel != null) {
422: displayedPanel.updateSavedState();
423: }
424: }
425: }
|