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