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.cpu.CPUResultsSnapshot;
045: import org.netbeans.lib.profiler.results.cpu.PrestimeCPUCCTNode;
046: import org.netbeans.lib.profiler.ui.UIConstants;
047: import org.netbeans.lib.profiler.ui.UIUtils;
048: import org.netbeans.lib.profiler.ui.components.JTreeTable;
049: import org.netbeans.lib.profiler.ui.components.table.CustomBarCellRenderer;
050: import org.netbeans.lib.profiler.ui.components.table.LabelBracketTableCellRenderer;
051: import org.netbeans.lib.profiler.ui.components.table.LabelTableCellRenderer;
052: import org.netbeans.lib.profiler.ui.components.table.SortableTableModel;
053: import org.netbeans.lib.profiler.ui.components.tree.EnhancedTreeCellRenderer;
054: import org.netbeans.lib.profiler.ui.components.tree.MethodNameTreeCellRenderer;
055: import org.netbeans.lib.profiler.ui.components.treetable.AbstractTreeTableModel;
056: import org.netbeans.lib.profiler.ui.components.treetable.ExtendedTreeTableModel;
057: import org.netbeans.lib.profiler.ui.components.treetable.JTreeTablePanel;
058: import org.netbeans.lib.profiler.ui.components.treetable.TreeTableModel;
059: import org.netbeans.lib.profiler.utils.StringUtils;
060: import java.awt.*;
061: import java.awt.event.*;
062: import java.awt.image.BufferedImage;
063: import java.text.MessageFormat;
064: import java.util.HashSet;
065: import java.util.ResourceBundle;
066: import java.util.Set;
067: import javax.swing.*;
068: import javax.swing.event.ListSelectionEvent;
069: import javax.swing.event.ListSelectionListener;
070: import javax.swing.table.TableCellRenderer;
071: import javax.swing.table.TableColumnModel;
072:
073: /**
074: * A display containing reverse call graph
075: *
076: * @author Misha Dmitriev
077: * @author Ian Formanek
078: * @author Jiri Sedlacek
079: * @author Jaroslav Bachorik
080: */
081: public class SubtreeCallGraphPanel extends SnapshotCPUResultsPanel
082: implements ScreenshotProvider {
083: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
084:
085: // -----
086: // I18N String constants
087: private static final ResourceBundle messages = ResourceBundle
088: .getBundle("org.netbeans.lib.profiler.ui.cpu.Bundle"); // NOI18N
089: private static final String PANEL_TITLE = messages
090: .getString("SubtreeCallGraphPanel_PanelTitle"); // NOI18N
091: private static final String PANEL_TITLE_SHORT = messages
092: .getString("SubtreeCallGraphPanel_PanelTitleShort"); // NOI18N
093: private static final String METHOD_COLUMN_NAME = messages
094: .getString("SubtreeCallGraphPanel_MethodColumnName"); // NOI18N
095: private static final String METHOD_COLUMN_TOOLTIP = messages
096: .getString("SubtreeCallGraphPanel_MethodColumnToolTip"); // NOI18N
097: private static final String CLASS_COLUMN_NAME = messages
098: .getString("SubtreeCallGraphPanel_ClassColumnName"); // NOI18N
099: private static final String CLASS_COLUMN_TOOLTIP = messages
100: .getString("SubtreeCallGraphPanel_ClassColumnToolTip"); // NOI18N
101: private static final String PACKAGE_COLUMN_NAME = messages
102: .getString("SubtreeCallGraphPanel_PackageColumnName"); // NOI18N
103: private static final String PACKAGE_COLUMN_TOOLTIP = messages
104: .getString("SubtreeCallGraphPanel_PackageColumnToolTip"); // NOI18N
105: private static final String TIME_REL_COLUMN_NAME = messages
106: .getString("SubtreeCallGraphPanel_TimeRelColumnName"); // NOI18N
107: private static final String TIME_REL_COLUMN_TOOLTIP = messages
108: .getString("SubtreeCallGraphPanel_TimeRelColumnToolTip"); // NOI18N
109: private static final String TIME_COLUMN_NAME = messages
110: .getString("SubtreeCallGraphPanel_TimeColumnName"); // NOI18N
111: private static final String TIME_COLUMN_TOOLTIP = messages
112: .getString("SubtreeCallGraphPanel_TimeColumnToolTip"); // NOI18N
113: private static final String TIME_CPU_COLUMN_NAME = messages
114: .getString("SubtreeCallGraphPanel_TimeCpuColumnName"); // NOI18N
115: private static final String TIME_CPU_COLUMN_TOOLTIP = messages
116: .getString("SubtreeCallGraphPanel_TimeCpuColumnToolTip"); // NOI18N
117: private static final String INVOCATIONS_COLUMN_NAME = messages
118: .getString("SubtreeCallGraphPanel_InvocationsColumnName"); // NOI18N
119: private static final String INVOCATIONS_COLUMN_TOOLTIP = messages
120: .getString("SubtreeCallGraphPanel_InvocationsColumnToolTip"); // NOI18N
121: private static final String TREETABLE_ACCESS_NAME = messages
122: .getString("SubtreeCallGraphPanel_TreeTableAccessName"); // NOI18N
123: // -----
124:
125: //~ Instance fields ----------------------------------------------------------------------------------------------------------
126:
127: protected JButton cornerButton;
128: protected JTreeTable treeTable;
129: protected JTreeTablePanel treeTablePanel;
130: protected PrestimeCPUCCTNode rootNode = null;
131: protected boolean sortOrder;
132: protected int sortingColumn;
133: private AbstractTreeTableModel abstractTreeTableModel;
134: private EnhancedTreeCellRenderer enhancedTreeCellRenderer = new MethodNameTreeCellRenderer();
135: private ExtendedTreeTableModel treeTableModel;
136: private ImageIcon leafIcon = new ImageIcon(
137: SubtreeCallGraphPanel.class
138: .getResource("/org/netbeans/lib/profiler/ui/resources/leaf.png")); // NOI18N
139: private ImageIcon nodeIcon = new ImageIcon(
140: SubtreeCallGraphPanel.class
141: .getResource("/org/netbeans/lib/profiler/ui/resources/node.png")); // NOI18N
142: private int minNamesColumnWidth; // minimal width of classnames columns
143:
144: //~ Constructors -------------------------------------------------------------------------------------------------------------
145:
146: public SubtreeCallGraphPanel(CPUResUserActionsHandler actionsHandler) {
147: super (actionsHandler);
148:
149: enhancedTreeCellRenderer.setLeafIcon(leafIcon);
150: enhancedTreeCellRenderer.setClosedIcon(nodeIcon);
151: enhancedTreeCellRenderer.setOpenIcon(nodeIcon);
152:
153: minNamesColumnWidth = getFontMetrics(getFont()).charWidth('W') * 30; // NOI18N
154:
155: cornerPopup = new JPopupMenu();
156: cornerButton = createHeaderPopupCornerButton(cornerPopup);
157:
158: setDefaultSorting();
159: }
160:
161: //~ Methods ------------------------------------------------------------------------------------------------------------------
162:
163: public int getCurrentThreadId() {
164: return (rootNode != null) ? rootNode.getThreadId() : 0;
165: }
166:
167: public BufferedImage getCurrentViewScreenshot(
168: boolean onlyVisibleArea) {
169: if ((treeTablePanel == null) || (treeTable == null)) {
170: return null;
171: }
172:
173: if (onlyVisibleArea) {
174: return UIUtils.createScreenshot(treeTablePanel
175: .getScrollPane());
176: } else {
177: return UIUtils.createScreenshot(treeTable);
178: }
179: }
180:
181: public void setDataToDisplay(CPUResultsSnapshot snapshot,
182: PrestimeCPUCCTNode node, int view) {
183: super .setDataToDisplay(snapshot, view);
184: this .rootNode = node;
185: popupShowSource.setEnabled(isShowSourceAvailable());
186: popupAddToRoots.setEnabled(isAddToRootsAvailable());
187: }
188:
189: // NOTE: this method only sets sortingColumn and sortOrder, it doesn't refresh UI!
190: public void setDefaultSorting() {
191: setSorting(1, SortableTableModel.SORT_ORDER_DESC);
192: }
193:
194: public String getDefaultViewName() {
195: return "cpu-subtree"; // NOI18N
196: }
197:
198: // --- Find functionality stuff
199: public void setFindString(String findString) {
200: treeTable.setFindParameters(findString, 0);
201: }
202:
203: public String getFindString() {
204: return treeTable.getFindString();
205: }
206:
207: public boolean isFindStringDefined() {
208: return treeTable.isFindStringDefined();
209: }
210:
211: public String getSelectedMethodName() {
212: int selectedMethodId = rootNode.getMethodId();
213: String name = snapshot.getInstrMethodClasses(currentView)[selectedMethodId];
214:
215: if (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW) {
216: name += ("."
217: + snapshot.getInstrMethodNames()[selectedMethodId] + snapshot
218: .getInstrMethodSignatures()[selectedMethodId]);
219: }
220:
221: return name;
222: }
223:
224: public String getSelectedMethodNameShort() {
225: int selectedMethodId = rootNode.getMethodId();
226:
227: if (currentView == CPUResultsSnapshot.METHOD_LEVEL_VIEW) {
228: return snapshot.getInstrMethodNames()[selectedMethodId];
229: } else {
230: return snapshot.getInstrMethodClasses(currentView)[selectedMethodId];
231: }
232: }
233:
234: public String getSelectedThreadName() {
235: int threadId = rootNode.getThreadId();
236:
237: return snapshot.getThreadNameForId(threadId);
238: }
239:
240: public String getShortTitle() {
241: return MessageFormat
242: .format(PANEL_TITLE_SHORT, new Object[] {
243: getSelectedThreadName(),
244: getSelectedMethodNameShort() });
245: }
246:
247: // NOTE: this method only sets sortingColumn and sortOrder, it doesn't refresh UI!
248: public void setSorting(int sColumn, boolean sOrder) {
249: if (sColumn == CommonConstants.SORTING_COLUMN_DEFAULT) {
250: setDefaultSorting();
251: } else {
252: sortingColumn = sColumn;
253: sortOrder = sOrder;
254: }
255: }
256:
257: public int getSortingColumn() {
258: return sortingColumn;
259: }
260:
261: public boolean getSortingOrder() {
262: return sortOrder;
263: }
264:
265: public String getTitle() {
266: return MessageFormat.format(PANEL_TITLE, new Object[] {
267: getSelectedThreadName(), getSelectedMethodName() });
268: }
269:
270: public boolean findFirst() {
271: return treeTable.findFirst();
272: }
273:
274: public boolean findNext() {
275: return treeTable.findNext();
276: }
277:
278: public boolean findPrevious() {
279: return treeTable.findPrevious();
280: }
281:
282: public boolean fitsVisibleArea() {
283: return !treeTablePanel.getScrollPane().getVerticalScrollBar()
284: .isEnabled();
285: }
286:
287: public void prepareResults() {
288: initColumnsData();
289:
290: // PrestimeCPUCCTNode newRoot = snapshot.getSubtreeCCT(rootNode, currentView);
291: initFirstColumnName();
292:
293: abstractTreeTableModel = new AbstractTreeTableModel(rootNode,
294: sortingColumn, sortOrder) {
295: public int getColumnCount() {
296: return columnCount;
297: }
298:
299: public String getColumnName(int column) {
300: return columnNames[column];
301: }
302:
303: public Class getColumnClass(int column) {
304: if (column == 0) {
305: return TreeTableModel.class;
306: } else {
307: return Object.class;
308: }
309: }
310:
311: public Object getValueAt(Object node, int column) {
312: if (!snapshot.isCollectingTwoTimeStamps()) {
313: if (column > 2) {
314: column += 1;
315: }
316: }
317:
318: PrestimeCPUCCTNode pNode = (PrestimeCPUCCTNode) node;
319:
320: switch (column) {
321: case 0:
322: return getNodeName(pNode);
323: case 1:
324: return getNodeTimeRel(pNode);
325: case 2:
326: return getNodeTime(pNode);
327: case 3:
328: return getNodeSecondaryTime(pNode);
329: case 4:
330: return getNodeInvocations(pNode);
331: }
332:
333: return null;
334: }
335:
336: public String getColumnToolTipText(int col) {
337: return columnToolTips[col];
338: }
339:
340: private String getNodeName(PrestimeCPUCCTNode pNode) {
341: return pNode.toString();
342: }
343:
344: private Float getNodeTimeRel(PrestimeCPUCCTNode pNode) {
345: return new Float(pNode.getTotalTime0InPerCent());
346: }
347:
348: private String getNodeTime(PrestimeCPUCCTNode pNode) {
349: return StringUtils.mcsTimeToString(pNode
350: .getTotalTime0())
351: + " ms (" // NOI18N
352: + percentFormat.format(pNode
353: .getTotalTime0InPerCent() / 100) + ")"; // NOI18N
354: }
355:
356: private String getNodeSecondaryTime(PrestimeCPUCCTNode pNode) {
357: /*!!! FIX THIS! if (pNode instanceof PresoCPUCCTClassNode) {
358: PresoCPUCCTClassNode.Extended extNode = (PresoCPUCCTClassNode.Extended)pNode;
359: return StringUtils.mcsTimeToString(extNode.getTotalTime1()) + " ms";
360: } else {*/
361: return StringUtils.mcsTimeToString(pNode
362: .getTotalTime1())
363: + " ms"; // NOI18N
364: }
365:
366: private Integer getNodeInvocations(PrestimeCPUCCTNode pNode) {
367: return new Integer(pNode.getNCalls());
368: }
369:
370: public void sortByColumn(int column, boolean order) {
371: sortOrder = order;
372:
373: if (!snapshot.isCollectingTwoTimeStamps()) {
374: if (column > 2) {
375: column += 1;
376: }
377: }
378:
379: PrestimeCPUCCTNode pRoot = (PrestimeCPUCCTNode) root;
380:
381: switch (column) {
382: case 0:
383: pRoot.sortChildren(PrestimeCPUCCTNode.SORT_BY_NAME,
384: order);
385:
386: break;
387: case 1:
388: pRoot.sortChildren(
389: PrestimeCPUCCTNode.SORT_BY_TIME_0, order);
390:
391: break;
392: case 2:
393: pRoot.sortChildren(
394: PrestimeCPUCCTNode.SORT_BY_TIME_0, order);
395:
396: break;
397: case 3:
398: /*!!! FIX THIS! if (pRoot instanceof PrestimeCPUCCTClassNode) {
399: pRoot.sortChildren(PrestimeCPUCCTClassNode.Extended.SORT_BY_TIME_1, order);
400: } else { */
401: pRoot.sortChildren(
402: PrestimeCPUCCTNode.SORT_BY_TIME_1, order);
403:
404: break;
405: case 4:
406: pRoot.sortChildren(
407: PrestimeCPUCCTNode.SORT_BY_INVOCATIONS,
408: order);
409:
410: break;
411: }
412: };
413:
414: public boolean getInitialSorting(int column) {
415: return (column == 0);
416: }
417: };
418:
419: treeTableModel = new ExtendedTreeTableModel(
420: abstractTreeTableModel);
421:
422: if (columnsVisibility != null) {
423: treeTableModel.setColumnsVisibility(columnsVisibility);
424: }
425:
426: treeTable = new JTreeTable(treeTableModel) {
427: public void doLayout() {
428: int columnsWidthsSum = 0;
429: int realFirstColumn = -1;
430:
431: int index;
432: TableColumnModel colModel = getColumnModel();
433:
434: for (int i = 0; i < treeTableModel.getColumnCount(); i++) {
435: index = treeTableModel.getRealColumn(i);
436:
437: if (index == 0) {
438: realFirstColumn = i;
439: } else {
440: columnsWidthsSum += colModel.getColumn(i)
441: .getPreferredWidth();
442: }
443: }
444:
445: if (realFirstColumn != -1) {
446: colModel.getColumn(realFirstColumn)
447: .setPreferredWidth(
448: Math.max(getWidth()
449: - columnsWidthsSum,
450: minNamesColumnWidth));
451: }
452:
453: super .doLayout();
454: };
455: };
456: treeTable.getAccessibleContext().setAccessibleName(
457: TREETABLE_ACCESS_NAME);
458:
459: treeTable.setRowSelectionAllowed(true);
460: treeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
461: treeTable.setGridColor(UIConstants.TABLE_VERTICAL_GRID_COLOR);
462: treeTable
463: .setSelectionBackground(UIConstants.TABLE_SELECTION_BACKGROUND_COLOR);
464: treeTable
465: .setSelectionForeground(UIConstants.TABLE_SELECTION_FOREGROUND_COLOR);
466: treeTable
467: .setShowHorizontalLines(UIConstants.SHOW_TABLE_HORIZONTAL_GRID);
468: treeTable
469: .setShowVerticalLines(UIConstants.SHOW_TABLE_VERTICAL_GRID);
470: treeTable.setRowMargin(UIConstants.TABLE_ROW_MARGIN);
471: treeTable.setRowHeight(UIUtils.getDefaultRowHeight() + 2);
472: treeTable
473: .getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
474: .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
475: "DEFAULT_ACTION"); // NOI18N
476: treeTable.getActionMap().put("DEFAULT_ACTION",
477: new AbstractAction() {
478: public void actionPerformed(ActionEvent e) {
479: performDefaultAction();
480: }
481: }); // NOI18N
482:
483: // Disable traversing table cells using TAB and Shift+TAB
484: Set keys = new HashSet(
485: treeTable
486: .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
487: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
488: treeTable.setFocusTraversalKeys(
489: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
490:
491: keys = new HashSet(
492: treeTable
493: .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
494: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
495: InputEvent.SHIFT_MASK));
496: treeTable.setFocusTraversalKeys(
497: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, keys);
498:
499: setColumnsData();
500:
501: UIUtils.autoExpandRoot(treeTable.getTree(), 2);
502: UIUtils.makeTreeAutoExpandable(treeTable.getTree(), 2);
503:
504: treeTable.addKeyListener(new KeyAdapter() {
505: public void keyPressed(KeyEvent e) {
506: if ((e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU)
507: || ((e.getKeyCode() == KeyEvent.VK_F10) && (e
508: .getModifiers() == InputEvent.SHIFT_MASK))) {
509: int selectedRow = treeTable.getSelectedRow();
510:
511: if (selectedRow != -1) {
512: popupPath = treeTable.getTree().getPathForRow(
513: selectedRow);
514:
515: Rectangle cellRect = treeTable.getCellRect(
516: selectedRow, 0, false);
517: callGraphPopupMenu
518: .show(
519: e.getComponent(),
520: ((cellRect.x + treeTable
521: .getSize().width) > 50) ? 50
522: : 5, cellRect.y);
523: }
524: }
525: }
526: });
527:
528: treeTable.addMouseListener(new MouseAdapter() {
529: public void mousePressed(MouseEvent e) {
530: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
531: popupPath = treeTable.getTree().getPathForRow(
532: treeTable.rowAtPoint(e.getPoint()));
533:
534: if (popupPath != null) {
535: treeTable.getTree().setSelectionPath(popupPath);
536: }
537: }
538: }
539:
540: public void mouseClicked(MouseEvent e) {
541: popupPath = treeTable.getTree().getPathForRow(
542: treeTable.rowAtPoint(e.getPoint()));
543:
544: if (popupPath == null) {
545: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
546: treeTable.getTree().clearSelection();
547: }
548: } else {
549: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
550: callGraphPopupMenu.show(e.getComponent(), e
551: .getX(), e.getY());
552: } else if ((e.getModifiers() == InputEvent.BUTTON1_MASK)
553: && (e.getClickCount() == 2)) {
554: if (treeTableModel
555: .isLeaf(popupPath.getPath()[popupPath
556: .getPath().length - 1])) {
557: showSourceForMethod(popupPath);
558: }
559: }
560: }
561: }
562: });
563:
564: treeTable.getSelectionModel().addListSelectionListener(
565: new ListSelectionListener() {
566: public void valueChanged(ListSelectionEvent e) {
567: int selectedRow = treeTable.getSelectedRow();
568:
569: if (selectedRow == -1) {
570: return;
571: }
572:
573: popupPath = treeTable.getTree().getPathForRow(
574: selectedRow);
575: }
576: });
577:
578: treeTablePanel = new JTreeTablePanel(treeTable);
579: treeTablePanel.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
580: cornerButton);
581: add(treeTablePanel, BorderLayout.CENTER);
582: }
583:
584: public void requestFocus() {
585: if (treeTable != null) {
586: SwingUtilities.invokeLater(new Runnable() { // must be invoked lazily to override default focus of first component (top-right cornerButton)
587: public void run() {
588: treeTable.requestFocus();
589: }
590: });
591: }
592: }
593:
594: public void reset() {
595: if (treeTablePanel != null) {
596: remove(treeTablePanel);
597: treeTablePanel = null;
598: }
599:
600: treeTable = null;
601: abstractTreeTableModel = null;
602: treeTableModel = null;
603: }
604:
605: protected boolean isCloseable() {
606: return true;
607: }
608:
609: protected void initColumnSelectorItems() {
610: cornerPopup.removeAll();
611:
612: JCheckBoxMenuItem menuItem;
613:
614: for (int i = 0; i < columnCount; i++) {
615: menuItem = new JCheckBoxMenuItem(columnNames[i]);
616: menuItem.setActionCommand(new Integer(i).toString());
617: addMenuItemListener(menuItem);
618:
619: if (treeTable != null) {
620: menuItem
621: .setState(treeTableModel.isRealColumnVisible(i));
622:
623: if (i == 0) {
624: menuItem.setEnabled(false);
625: }
626: } else {
627: menuItem.setState(true);
628: }
629:
630: cornerPopup.add(menuItem);
631: }
632:
633: cornerPopup.pack();
634: }
635:
636: private void setColumnsData() {
637: int index;
638: TableColumnModel colModel = treeTable.getColumnModel();
639:
640: treeTable.setTreeCellRenderer(enhancedTreeCellRenderer);
641: colModel.getColumn(0).setPreferredWidth(minNamesColumnWidth);
642:
643: for (int i = 0; i < treeTableModel.getColumnCount(); i++) {
644: index = treeTableModel.getRealColumn(i);
645:
646: if (index != 0) {
647: colModel.getColumn(i).setPreferredWidth(
648: columnWidths[index - 1]);
649: colModel.getColumn(i).setCellRenderer(
650: columnRenderers[index]);
651: }
652: }
653: }
654:
655: // protected JPopupMenu createPopupMenu() {
656: // JPopupMenu popup = new JPopupMenu();
657: // popupShowSource = new JMenuItem();
658: // popupShowSubtree = new JMenuItem();
659: // popupShowReverse = new JMenuItem();
660: // popupAddToRoots = new JMenuItem();
661: //
662: // Font boldfont = popup.getFont ().deriveFont(Font.BOLD);
663: //
664: // popupShowSource.setFont(boldfont);
665: // popupShowSource.setText(GO_TO_SOURCE_POPUP_ITEM);
666: // popup.add(popupShowSource);
667: //
668: // popup.addSeparator();
669: //
670: // popupAddToRoots.setText(ADD_ROOT_METHOD_POPUP_ITEM);
671: // popup.add(popupAddToRoots);
672: //
673: // ActionListener menuListener = new ActionListener() {
674: // public void actionPerformed(ActionEvent evt) {
675: // menuActionPerformed(evt);
676: // }
677: // };
678: //
679: // popupShowSource.addActionListener(menuListener);
680: // popupAddToRoots.addActionListener(menuListener);
681: //
682: // return popup;
683: // }
684: private void addMenuItemListener(JCheckBoxMenuItem menuItem) {
685: menuItem.addActionListener(new ActionListener() {
686: public void actionPerformed(ActionEvent e) {
687: boolean sortResults = false;
688: int column = Integer.parseInt(e.getActionCommand());
689: boolean sortOrder = treeTable.getSortingOrder();
690: int sortingColumn = treeTable.getSortingColumn();
691: int realSortingColumn = treeTableModel
692: .getRealColumn(sortingColumn);
693: boolean isColumnVisible = treeTableModel
694: .isRealColumnVisible(column);
695:
696: // Current sorting column is going to be hidden
697: if ((isColumnVisible) && (column == realSortingColumn)) {
698: // Try to set next column as a sortingColumn. If currentSortingColumn is the last column, set previous
699: // column as a sorting Column (one column is always visible).
700: sortingColumn = ((sortingColumn + 1) == treeTableModel
701: .getColumnCount()) ? (sortingColumn - 1)
702: : (sortingColumn + 1);
703: realSortingColumn = treeTableModel
704: .getRealColumn(sortingColumn);
705: sortResults = true;
706: }
707:
708: treeTableModel.setRealColumnVisibility(column,
709: !isColumnVisible);
710: treeTable.createDefaultColumnsFromModel();
711: treeTable.updateTreeTableHeader();
712: sortingColumn = treeTableModel
713: .getVirtualColumn(realSortingColumn);
714:
715: if (sortResults) {
716: sortOrder = treeTableModel
717: .getInitialSorting(sortingColumn);
718: treeTableModel.sortByColumn(sortingColumn,
719: sortOrder);
720: treeTable.updateTreeTable();
721: }
722:
723: treeTable.setSortingColumn(sortingColumn);
724: treeTable.setSortingOrder(sortOrder);
725: treeTable.getTableHeader().repaint();
726: setColumnsData();
727:
728: // TODO [ui-persistence]
729: }
730: });
731: }
732:
733: private void initColumnsData() {
734: columnCount = snapshot.isCollectingTwoTimeStamps() ? 5 : 4;
735:
736: columnWidths = new int[columnCount - 1]; // Width of the first column fits to width
737: columnNames = new String[columnCount];
738: columnRenderers = new TableCellRenderer[columnCount];
739: columnsVisibility = null;
740:
741: if (columnCount == 5) {
742: columnNames = new String[] { METHOD_COLUMN_NAME,
743: TIME_REL_COLUMN_NAME, TIME_COLUMN_NAME,
744: TIME_CPU_COLUMN_NAME, INVOCATIONS_COLUMN_NAME };
745: columnToolTips = new String[] { METHOD_COLUMN_TOOLTIP,
746: TIME_REL_COLUMN_TOOLTIP, TIME_COLUMN_TOOLTIP,
747: TIME_CPU_COLUMN_TOOLTIP, INVOCATIONS_COLUMN_TOOLTIP };
748: } else {
749: columnNames = new String[] { METHOD_COLUMN_NAME,
750: TIME_REL_COLUMN_NAME, TIME_COLUMN_NAME,
751: INVOCATIONS_COLUMN_NAME };
752: columnToolTips = new String[] { METHOD_COLUMN_TOOLTIP,
753: TIME_REL_COLUMN_TOOLTIP, TIME_COLUMN_TOOLTIP,
754: INVOCATIONS_COLUMN_TOOLTIP };
755: }
756:
757: int maxWidth = getFontMetrics(getFont()).charWidth('W') * 12; // NOI18N // initial width of data columns
758:
759: CustomBarCellRenderer customBarCellRenderer = new CustomBarCellRenderer(
760: 0, 100);
761: LabelTableCellRenderer labelTableCellRenderer = new LabelTableCellRenderer(
762: JLabel.TRAILING);
763: LabelBracketTableCellRenderer labelBracketTableCellRenderer = new LabelBracketTableCellRenderer(
764: JLabel.TRAILING);
765:
766: columnRenderers[0] = null;
767:
768: // Inclusive (total) time bar
769: columnWidths[1 - 1] = maxWidth;
770: columnRenderers[1] = customBarCellRenderer;
771:
772: // Inclusive (total) time
773: columnWidths[2 - 1] = maxWidth;
774: columnRenderers[2] = labelBracketTableCellRenderer;
775:
776: for (int i = 3; i < columnCount; i++) {
777: columnWidths[i - 1] = maxWidth;
778: columnRenderers[i] = labelTableCellRenderer;
779: }
780: }
781:
782: private void initFirstColumnName() {
783: switch (currentView) {
784: case CPUResultsSnapshot.METHOD_LEVEL_VIEW:
785: columnNames[0] = METHOD_COLUMN_NAME;
786: columnToolTips[0] = METHOD_COLUMN_TOOLTIP;
787:
788: break;
789: case CPUResultsSnapshot.CLASS_LEVEL_VIEW:
790: columnNames[0] = CLASS_COLUMN_NAME;
791: columnToolTips[0] = CLASS_COLUMN_TOOLTIP;
792:
793: break;
794: case CPUResultsSnapshot.PACKAGE_LEVEL_VIEW:
795: columnNames[0] = PACKAGE_COLUMN_NAME;
796: columnToolTips[0] = PACKAGE_COLUMN_TOOLTIP;
797:
798: break;
799: }
800: }
801: }
|