0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: * The Original Software is NetBeans. The Initial Developer of the Original
0026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0027: * Microsystems, Inc. All Rights Reserved.
0028: *
0029: * If you wish your version of this file to be governed by only the CDDL
0030: * or only the GPL Version 2, indicate your decision by adding
0031: * "[Contributor] elects to include this software in this distribution
0032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0033: * single choice of license, a recipient has the option to distribute
0034: * your version of this file under either the CDDL, the GPL Version 2 or
0035: * to extend the choice of license to its licensees as provided above.
0036: * However, if you add GPL Version 2 code and therefore, elected the GPL
0037: * Version 2 license, then the option applies only if the new code is
0038: * made subject to such option by the copyright holder.
0039: */
0040:
0041: package org.netbeans.lib.profiler.ui.cpu;
0042:
0043: import org.netbeans.lib.profiler.global.CommonConstants;
0044: import org.netbeans.lib.profiler.results.cpu.CPUResultsSnapshot;
0045: import org.netbeans.lib.profiler.results.cpu.FlatProfileContainer;
0046: import org.netbeans.lib.profiler.ui.UIConstants;
0047: import org.netbeans.lib.profiler.ui.UIUtils;
0048: import org.netbeans.lib.profiler.ui.components.FilterComponent;
0049: import org.netbeans.lib.profiler.ui.components.JExtendedTable;
0050: import org.netbeans.lib.profiler.ui.components.table.ClassNameTableCellRenderer;
0051: import org.netbeans.lib.profiler.ui.components.table.CustomBarCellRenderer;
0052: import org.netbeans.lib.profiler.ui.components.table.ExtendedTableModel;
0053: import org.netbeans.lib.profiler.ui.components.table.LabelBracketTableCellRenderer;
0054: import org.netbeans.lib.profiler.ui.components.table.LabelTableCellRenderer;
0055: import org.netbeans.lib.profiler.ui.components.table.MethodNameTableCellRenderer;
0056: import org.netbeans.lib.profiler.ui.components.table.SortableTableModel;
0057: import org.netbeans.lib.profiler.utils.StringUtils;
0058: import java.awt.*;
0059: import java.awt.event.*;
0060: import java.util.HashSet;
0061: import java.util.ResourceBundle;
0062: import java.util.Set;
0063: import javax.swing.*;
0064: import javax.swing.event.ListSelectionEvent;
0065: import javax.swing.event.ListSelectionListener;
0066: import javax.swing.table.TableCellRenderer;
0067: import javax.swing.table.TableColumnModel;
0068:
0069: /**
0070: * A common abstract superclass for Hotspots display containing a flat profile.
0071: * <p/>
0072: * The subclasses need to implement these methods:
0073: * obtainResults () to initialize the data either from snapshot or from live data.
0074: * getTitle () to provide title for the panel
0075: * getMethodClassNameAndSig () to map methodId to class/method names
0076: * supportsReverseCallGraph () to declare if displaying reverse call graph is supported
0077: * showReverseCallGraph () to display the reverse call graph (utilizing actionsHandler)
0078: *
0079: * @author Misha Dmitriev
0080: * @author Ian Formanek
0081: * @author Jiri Sedlacek
0082: */
0083: public abstract class FlatProfilePanel extends CPUResultsPanel {
0084: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
0085:
0086: // -----
0087: // I18N String constants
0088: private static final ResourceBundle messages = ResourceBundle
0089: .getBundle("org.netbeans.lib.profiler.ui.cpu.Bundle"); // NOI18N
0090: private static final String STARTS_WITH_STRING = messages
0091: .getString("FlatProfilePanel_StartsWithString"); // NOI18N
0092: private static final String CONTAINS_STRING = messages
0093: .getString("FlatProfilePanel_ContainsString"); // NOI18N
0094: private static final String ENDS_WITH_STRING = messages
0095: .getString("FlatProfilePanel_EndsWithString"); // NOI18N
0096: private static final String REGEXP_STRING = messages
0097: .getString("FlatProfilePanel_RegExpString"); // NOI18N
0098: private static final String FILTER_ITEM_NAME = messages
0099: .getString("FlatProfilePanel_FilterItemName"); // NOI18N
0100: private static final String METHOD_COLUMN_NAME = messages
0101: .getString("FlatProfilePanel_MethodColumnName"); // NOI18N
0102: private static final String METHOD_COLUMN_TOOLTIP = messages
0103: .getString("FlatProfilePanel_MethodColumnToolTip"); // NOI18N
0104: private static final String METHOD_FILTER_HINT = messages
0105: .getString("FlatProfilePanel_MethodFilterHint"); // NOI18N
0106: private static final String CLASS_COLUMN_NAME = messages
0107: .getString("FlatProfilePanel_ClassColumnName"); // NOI18N
0108: private static final String CLASS_COLUMN_TOOLTIP = messages
0109: .getString("FlatProfilePanel_ClassColumnToolTip"); // NOI18N
0110: private static final String CLASS_FILTER_HINT = messages
0111: .getString("FlatProfilePanel_ClassFilterHint"); // NOI18N
0112: private static final String PACKAGE_COLUMN_NAME = messages
0113: .getString("FlatProfilePanel_PackageColumnName"); // NOI18N
0114: private static final String PACKAGE_COLUMN_TOOLTIP = messages
0115: .getString("FlatProfilePanel_PackageColumnToolTip"); // NOI18N
0116: private static final String PACKAGE_FILTER_HINT = messages
0117: .getString("FlatProfilePanel_PackageFilterHint"); // NOI18N
0118: private static final String SELFTIME_REL_COLUMN_NAME = messages
0119: .getString("FlatProfilePanel_SelfTimeRelColumnName"); // NOI18N
0120: private static final String SELFTIME_REL_COLUMN_TOOLTIP = messages
0121: .getString("FlatProfilePanel_SelfTimeRelColumnToolTip"); // NOI18N
0122: private static final String SELFTIME_COLUMN_NAME = messages
0123: .getString("FlatProfilePanel_SelfTimeColumnName"); // NOI18N
0124: private static final String SELFTIME_COLUMN_TOOLTIP = messages
0125: .getString("FlatProfilePanel_SelfTimeColumnToolTip"); // NOI18N
0126: private static final String SELFTIME_CPU_COLUMN_NAME = messages
0127: .getString("FlatProfilePanel_SelfTimeCpuColumnName"); // NOI18N
0128: private static final String SELFTIME_CPU_COLUMN_TOOLTIP = messages
0129: .getString("FlatProfilePanel_SelfTimeCpuColumnToolTip"); // NOI18N
0130: private static final String INVOCATIONS_COLUMN_NAME = messages
0131: .getString("FlatProfilePanel_InvocationsColumnName"); // NOI18N
0132: private static final String INVOCATIONS_COLUMN_TOOLTIP = messages
0133: .getString("FlatProfilePanel_InvocationsColumnToolTip"); // NOI18N
0134: private static final String TABLE_ACCESS_NAME = messages
0135: .getString("FlatProfilePanel_TableAccessName"); // NOI18N
0136: // -----
0137:
0138: //~ Instance fields ----------------------------------------------------------------------------------------------------------
0139:
0140: //float maxValue;
0141: protected CustomBarCellRenderer barRenderer;
0142: protected ExtendedTableModel resTableModel;
0143: protected FilterComponent filterComponent;
0144: protected FlatProfileContainer flatProfileContainer;
0145: protected JExtendedTable resTable;
0146: protected JScrollPane jScrollPane;
0147: protected String filterString = ""; // NOI18N
0148: protected boolean collectingTwoTimeStamps;
0149: protected boolean sortOrder;
0150: protected double valueFilterValue = 0.0d;
0151: protected int filterType = CommonConstants.FILTER_CONTAINS;
0152: protected int sortBy;
0153: protected int threadId;
0154: private CPUSelectionHandler selectionHandler;
0155: private JPanel noDataPanel;
0156: private int minNamesColumnWidth; // minimal width of classnames columns
0157: private int sortingColumn;
0158:
0159: //~ Constructors -------------------------------------------------------------------------------------------------------------
0160:
0161: public FlatProfilePanel(CPUResUserActionsHandler actionsHandler) {
0162: this (actionsHandler, null);
0163: }
0164:
0165: public FlatProfilePanel(CPUResUserActionsHandler actionsHandler,
0166: CPUSelectionHandler selectionHandler) {
0167: super (actionsHandler);
0168: this .selectionHandler = selectionHandler;
0169: setDefaultSorting();
0170:
0171: minNamesColumnWidth = getFontMetrics(getFont()).charWidth('W') * 30; // NOI18N
0172:
0173: cornerPopup = new JPopupMenu();
0174:
0175: jScrollPane = createScrollPaneVerticalScrollBarAlways();
0176: jScrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
0177: createHeaderPopupCornerButton(cornerPopup));
0178: jScrollPane.addMouseWheelListener(new MouseWheelListener() {
0179: public void mouseWheelMoved(MouseWheelEvent e) {
0180: if (resTable != null) {
0181: resTable.mouseWheelMoved(e);
0182: }
0183: }
0184: });
0185: initFilterPanel();
0186: }
0187:
0188: //~ Methods ------------------------------------------------------------------------------------------------------------------
0189:
0190: public void setCPUSelectionHandler(CPUSelectionHandler handler) {
0191: selectionHandler = handler;
0192: }
0193:
0194: @Override
0195: public int getCurrentThreadId() {
0196: return threadId;
0197: }
0198:
0199: // NOTE: this method only sets sortingColumn, sortOrder and sortBy, it doesn't refresh UI!
0200: public void setDefaultSorting() {
0201: setSorting(1, SortableTableModel.SORT_ORDER_DESC);
0202: }
0203:
0204: public int getFilterType() {
0205: return filterComponent.getFilterType();
0206: }
0207:
0208: public String getFilterValue() {
0209: return filterComponent.getFilterString();
0210: }
0211:
0212: public void setFilterValues(String filterValue, int filterType) {
0213: filterComponent.setFilterValues(filterValue, filterType);
0214: }
0215:
0216: /* private void printPercents() {
0217: double sum = 0;
0218:
0219: for (int i = 0; i < flatProfileContainer.getNRows(); i++) {
0220: sum += flatProfileContainer.getPercentAtRow(i);
0221: }
0222:
0223: System.err.println("Sum: "+sum);
0224: }
0225: */
0226:
0227: // --- Find functionality stuff
0228: public void setFindString(String findString) {
0229: resTable.setFindParameters(findString, 0);
0230: }
0231:
0232: public String getFindString() {
0233: return resTable.getFindString();
0234: }
0235:
0236: public boolean isFindStringDefined() {
0237: return resTable.isFindStringDefined();
0238: }
0239:
0240: public void setResultsAvailable(boolean available) {
0241: jScrollPane.setViewportView(available ? resTable : noDataPanel);
0242: revalidate();
0243: repaint();
0244: }
0245:
0246: public Object getResultsViewReference() {
0247: return resTable;
0248: }
0249:
0250: public int getSortBy(int column) {
0251: switch (column) {
0252: case 0:
0253: return FlatProfileContainer.SORT_BY_NAME;
0254: case 1:
0255: case 2:
0256: return FlatProfileContainer.SORT_BY_TIME;
0257: case 3:
0258: return collectingTwoTimeStamps ? FlatProfileContainer.SORT_BY_SECONDARY_TIME
0259: : FlatProfileContainer.SORT_BY_INV_NUMBER;
0260: case 4:
0261: return FlatProfileContainer.SORT_BY_INV_NUMBER;
0262: }
0263:
0264: return FlatProfileContainer.SORT_BY_TIME;
0265: }
0266:
0267: // NOTE: this method only sets sortingColumn, sortOrder and sortBy, it doesn't refresh UI!
0268: public void setSorting(int sColumn, boolean sOrder) {
0269: if (sColumn == CommonConstants.SORTING_COLUMN_DEFAULT) {
0270: setDefaultSorting();
0271: } else {
0272: sortingColumn = sColumn;
0273: sortOrder = sOrder;
0274: sortBy = getSortBy(sortingColumn);
0275: }
0276: }
0277:
0278: @Override
0279: public int getSortingColumn() {
0280: if (resTableModel == null) {
0281: return CommonConstants.SORTING_COLUMN_DEFAULT;
0282: }
0283:
0284: return resTableModel.getRealColumn(resTableModel
0285: .getSortingColumn());
0286: }
0287:
0288: @Override
0289: public boolean getSortingOrder() {
0290: if (resTableModel == null) {
0291: return false;
0292: }
0293:
0294: return resTableModel.getSortingOrder();
0295: }
0296:
0297: public void addFilterListener(
0298: FilterComponent.FilterListener listener) {
0299: filterComponent.addFilterListener(listener);
0300: }
0301:
0302: public void addResultsViewFocusListener(FocusListener listener) {
0303: resTable.addFocusListener(listener);
0304: }
0305:
0306: public boolean findFirst() {
0307: return resTable.findFirst();
0308: }
0309:
0310: public boolean findNext() {
0311: return resTable.findNext();
0312: }
0313:
0314: public boolean findPrevious() {
0315: return resTable.findPrevious();
0316: }
0317:
0318: @Override
0319: public void prepareResults() {
0320: prepareResults(true);
0321: }
0322:
0323: public void removeFilterListener(
0324: FilterComponent.FilterListener listener) {
0325: filterComponent.removeFilterListener(listener);
0326: }
0327:
0328: public void removeResultsViewFocusListener(FocusListener listener) {
0329: resTable.removeFocusListener(listener);
0330: }
0331:
0332: @Override
0333: public void requestFocus() {
0334: if (resTable != null) {
0335: SwingUtilities.invokeLater(new Runnable() { // must be invoked lazily to override default focus of first component (top-right cornerButton)
0336: public void run() {
0337: resTable.requestFocus();
0338: }
0339: });
0340: }
0341: }
0342:
0343: // ---
0344:
0345: // components are discarded between profiling sessions
0346: @Override
0347: public void reset() {
0348: jScrollPane.setViewportView(null);
0349: flatProfileContainer = null;
0350: resTable = null;
0351: resTableModel = null;
0352: }
0353:
0354: public void selectMethod(int methodId) {
0355: // System.err.println("Select method: "+methodId);
0356: if (methodId == 0) {
0357: resTable.getSelectionModel().clearSelection();
0358:
0359: return;
0360: }
0361:
0362: int sel = resTable.getSelectedRow();
0363:
0364: if (sel >= flatProfileContainer.getNRows()) {
0365: sel = flatProfileContainer.getNRows() - 1; // no idea how can this happen, but it happens - see #100355
0366: }
0367:
0368: if ((sel != -1)
0369: && (getCurrentThreadId() == threadId)
0370: && (flatProfileContainer.getMethodIdAtRow(sel) == methodId)) {
0371: return; // the right method is already selected
0372: }
0373:
0374: // lookup the row index with the matching methodId
0375: for (int i = 0; i < flatProfileContainer.getNRows(); i++) {
0376: // System.err.println("Checking: "+flatProfileContainer.getMethodIdAtRow(i));
0377: if (flatProfileContainer.getMethodIdAtRow(i) == methodId) {
0378: resTable.getSelectionModel().setSelectionInterval(i, i);
0379: resTable.scrollRectToVisible(resTable.getCellRect(i, 0,
0380: true));
0381:
0382: break;
0383: }
0384: }
0385: }
0386:
0387: public void selectMethod(String methodName) {
0388: for (int i = 0; i < resTable.getRowCount(); i++) {
0389: if (resTable.getValueAt(i, 0).toString().equals(methodName)) {
0390: resTable.getSelectionModel().setSelectionInterval(i, i);
0391: resTable.scrollRectToVisible(resTable.getCellRect(i, 0,
0392: true));
0393:
0394: return;
0395: }
0396: }
0397:
0398: resTable.getSelectionModel().clearSelection();
0399: }
0400:
0401: @Override
0402: protected String getSelectedMethodName() {
0403: if ((resTable == null) || (resTableModel == null)) {
0404: return null;
0405: }
0406:
0407: if (resTable.getSelectedRow() == -1) {
0408: return null;
0409: }
0410:
0411: return resTable.getValueAt(resTable.getSelectedRow(), 0)
0412: .toString();
0413: }
0414:
0415: @Override
0416: protected void initColumnSelectorItems() {
0417: cornerPopup.removeAll();
0418:
0419: JCheckBoxMenuItem menuItem;
0420:
0421: for (int i = 0; i < columnCount; i++) {
0422: menuItem = new JCheckBoxMenuItem(columnNames[i]);
0423: menuItem.setActionCommand(new Integer(i).toString());
0424: addMenuItemListener(menuItem);
0425:
0426: if (resTable != null) {
0427: menuItem.setState(resTableModel.isRealColumnVisible(i));
0428:
0429: if (i == 0) {
0430: menuItem.setEnabled(false);
0431: }
0432: } else {
0433: menuItem.setState(true);
0434: }
0435:
0436: cornerPopup.add(menuItem);
0437: }
0438:
0439: cornerPopup.addSeparator();
0440:
0441: JCheckBoxMenuItem filterMenuItem = new JCheckBoxMenuItem(
0442: FILTER_ITEM_NAME);
0443: filterMenuItem.setActionCommand("Filter"); // NOI18N
0444: addMenuItemListener(filterMenuItem);
0445:
0446: if (filterComponent == null) {
0447: filterMenuItem.setState(true);
0448: } else {
0449: filterMenuItem.setState(filterComponent.isVisible());
0450: }
0451:
0452: cornerPopup.add(filterMenuItem);
0453:
0454: cornerPopup.pack();
0455: }
0456:
0457: protected void initColumnsData() {
0458: columnCount = collectingTwoTimeStamps ? 5 : 4;
0459:
0460: columnsVisibility = null;
0461:
0462: columnWidths = new int[columnCount - 1]; // Width of the first column fits to width
0463: columnNames = new String[columnCount];
0464: columnToolTips = new String[columnCount];
0465: columnRenderers = new TableCellRenderer[columnCount];
0466:
0467: columnNames[0] = METHOD_COLUMN_NAME;
0468: columnToolTips[0] = METHOD_COLUMN_TOOLTIP;
0469:
0470: columnNames[1] = SELFTIME_REL_COLUMN_NAME;
0471: columnToolTips[1] = SELFTIME_REL_COLUMN_TOOLTIP;
0472:
0473: columnNames[2] = SELFTIME_COLUMN_NAME;
0474: columnToolTips[2] = SELFTIME_COLUMN_TOOLTIP;
0475:
0476: if (collectingTwoTimeStamps) {
0477: columnNames[3] = SELFTIME_CPU_COLUMN_NAME;
0478: columnToolTips[3] = SELFTIME_CPU_COLUMN_TOOLTIP;
0479: columnNames[4] = INVOCATIONS_COLUMN_NAME;
0480: columnToolTips[4] = INVOCATIONS_COLUMN_TOOLTIP;
0481: } else { // just absolute
0482: columnNames[3] = INVOCATIONS_COLUMN_NAME;
0483: columnToolTips[3] = INVOCATIONS_COLUMN_TOOLTIP;
0484: }
0485:
0486: int maxWidth = getFontMetrics(getFont()).charWidth('W') * 12; // NOI18N // initial width of data columns
0487:
0488: CustomBarCellRenderer customBarCellRenderer = new CustomBarCellRenderer(
0489: 0, 100);
0490: LabelTableCellRenderer labelTableCellRenderer = new LabelTableCellRenderer(
0491: JLabel.TRAILING);
0492: LabelBracketTableCellRenderer labelBracketTableCellRenderer = new LabelBracketTableCellRenderer(
0493: JLabel.TRAILING);
0494:
0495: // method / class / package name
0496: columnRenderers[0] = null;
0497:
0498: columnWidths[1 - 1] = maxWidth;
0499: columnRenderers[1] = customBarCellRenderer;
0500:
0501: columnWidths[2 - 1] = maxWidth;
0502: columnRenderers[2] = labelBracketTableCellRenderer;
0503:
0504: for (int i = 3; i < columnCount; i++) {
0505: columnWidths[i - 1] = maxWidth;
0506: columnRenderers[i] = labelTableCellRenderer;
0507: }
0508: }
0509:
0510: /* public void updateValueFilter(double value) {
0511: System.err.println("Update value filter to: "+value);
0512:
0513: valueFilterValue = value/3f; // maximum 33.3%
0514:
0515: flatProfileContainer.filterOriginalData(
0516: FilterComponent.getFilterStrings(filterString), filterType, valueFilterValue);
0517: flatProfileContainer.sortBy(sortBy, sortOrder);
0518: resTable.invalidate();
0519: jScrollPane.revalidate();
0520: resTable.repaint();
0521: } */
0522: protected abstract void obtainResults();
0523:
0524: /**
0525: * If firstTime is true, it means we need to go and get results from the CCT, which means walking the
0526: * nodes of the CCT and doing some calculations, i.e. non-zero cost. Otherwise, we just use the cached
0527: * results in flatProfileContainer, and sort them by the current sorting criterion.
0528: */
0529: protected void prepareResults(boolean firstTime) {
0530: if (threadId < -1) {
0531: return; // -1 is reserved for all threads merged flat profile;
0532: }
0533:
0534: // non-negative numbers are actual thread ids
0535: int currentColumnCount = collectingTwoTimeStamps ? 5 : 4;
0536:
0537: if (columnCount != currentColumnCount) {
0538: initColumnsData();
0539: } else {
0540: if (resTable != null) {
0541: saveColumnsData();
0542: }
0543: }
0544:
0545: // first create the UI component model
0546: if ((resTableModel == null) || (resTable == null)) {
0547: initComponents(); // new components (table & tableModel) are created for each profiling session
0548: }
0549:
0550: // then try to fetch some data
0551: if (firstTime) {
0552: obtainResults(); // This also sorts the results by the appropriate timer
0553:
0554: String firstColumnName = columnNames[0];
0555: initFirstColumnName();
0556:
0557: if ((resTable != null)
0558: && !columnNames[0].equals(firstColumnName)) {
0559: resTable.getColumnModel().getColumn(0).setHeaderValue(
0560: columnNames[0]);
0561: }
0562: }
0563:
0564: flatProfileContainer.sortBy(sortBy, sortOrder);
0565:
0566: // resTable.clearSelection();
0567: resTable.invalidate();
0568: jScrollPane.revalidate();
0569: resTable.repaint();
0570: }
0571:
0572: protected void saveColumnsData() {
0573: int index;
0574: TableColumnModel colModel = resTable.getColumnModel();
0575:
0576: for (int i = 0; i < resTableModel.getColumnCount(); i++) {
0577: index = resTableModel.getRealColumn(i);
0578:
0579: if (index != 0) {
0580: columnWidths[index - 1] = colModel.getColumn(i)
0581: .getPreferredWidth();
0582: }
0583: }
0584:
0585: columnsVisibility = null;
0586: columnsVisibility = resTableModel.getColumnsVisibility();
0587: }
0588:
0589: protected void updateResults() {
0590: if (threadId < -1) {
0591: return; // -1 is reserved for all threads merged flat profile;
0592: }
0593:
0594: // non-negative numbers are actual thread ids
0595: int currentColumnCount = collectingTwoTimeStamps ? 5 : 4;
0596:
0597: if (columnCount != currentColumnCount) {
0598: initColumnsData();
0599: } else {
0600: if (resTable != null) {
0601: saveColumnsData();
0602: }
0603: }
0604:
0605: flatProfileContainer.sortBy(sortBy, sortOrder);
0606:
0607: jScrollPane.setViewportView(resTable);
0608: jScrollPane.getViewport().setBackground(
0609: resTable.getBackground());
0610: }
0611:
0612: private void setColumnsData() {
0613: switch (currentView) {
0614: case CPUResultsSnapshot.METHOD_LEVEL_VIEW:
0615: columnRenderers[0] = new MethodNameTableCellRenderer();
0616:
0617: break;
0618: case CPUResultsSnapshot.CLASS_LEVEL_VIEW:
0619: columnRenderers[0] = new ClassNameTableCellRenderer();
0620:
0621: break;
0622: case CPUResultsSnapshot.PACKAGE_LEVEL_VIEW:
0623: columnRenderers[0] = new LabelTableCellRenderer();
0624:
0625: break;
0626: }
0627:
0628: int index;
0629: TableColumnModel colModel = resTable.getColumnModel();
0630:
0631: for (int i = 0; i < resTableModel.getColumnCount(); i++) {
0632: index = resTableModel.getRealColumn(i);
0633:
0634: if (index == 0) {
0635: colModel.getColumn(i).setPreferredWidth(
0636: minNamesColumnWidth);
0637: } else {
0638: colModel.getColumn(i).setPreferredWidth(
0639: columnWidths[index - 1]);
0640: }
0641:
0642: colModel.getColumn(i).setCellRenderer(
0643: columnRenderers[index]);
0644: }
0645: }
0646:
0647: private void addMenuItemListener(JCheckBoxMenuItem menuItem) {
0648: menuItem.addActionListener(new java.awt.event.ActionListener() {
0649: public void actionPerformed(java.awt.event.ActionEvent e) {
0650: if (e.getActionCommand().equals("Filter")) { // NOI18N
0651: filterComponent.setVisible(!filterComponent
0652: .isVisible());
0653:
0654: return;
0655: }
0656:
0657: boolean sortResults = false;
0658: int column = Integer.parseInt(e.getActionCommand());
0659: int currentSortingColumn = resTableModel
0660: .getSortingColumn();
0661: int realSortingColumn = resTableModel
0662: .getRealColumn(currentSortingColumn);
0663: boolean isColumnVisible = resTableModel
0664: .isRealColumnVisible(column);
0665:
0666: // Current sorting column is going to be hidden
0667: if ((isColumnVisible) && (column == realSortingColumn)) {
0668: // Try to set next column as a currentSortingColumn. If currentSortingColumn is the last column,
0669: // set previous column as a sorting Column (one column is always visible).
0670: currentSortingColumn = ((currentSortingColumn + 1) == resTableModel
0671: .getColumnCount()) ? (currentSortingColumn - 1)
0672: : (currentSortingColumn + 1);
0673: realSortingColumn = resTableModel
0674: .getRealColumn(currentSortingColumn);
0675: sortResults = true;
0676: }
0677:
0678: resTableModel.setRealColumnVisibility(column,
0679: !isColumnVisible);
0680: resTable.createDefaultColumnsFromModel();
0681: resTableModel.setTable(resTable);
0682: currentSortingColumn = resTableModel
0683: .getVirtualColumn(realSortingColumn);
0684:
0685: if (sortResults) {
0686: sortOrder = resTableModel
0687: .getInitialSorting(currentSortingColumn);
0688: sortBy = getSortBy(realSortingColumn);
0689: flatProfileContainer.sortBy(sortBy, sortOrder);
0690: resTable.repaint();
0691: }
0692:
0693: sortingColumn = realSortingColumn;
0694: resTableModel.setInitialSorting(currentSortingColumn,
0695: sortOrder);
0696: resTable.getTableHeader().repaint();
0697: setColumnsData();
0698:
0699: // TODO [ui-persistence]
0700: }
0701: });
0702: }
0703:
0704: private void initComponents() {
0705: resTableModel = new ExtendedTableModel(
0706: new SortableTableModel() {
0707: @Override
0708: public String getColumnName(int col) {
0709: return columnNames[col];
0710: }
0711:
0712: public int getRowCount() {
0713: if (flatProfileContainer == null) {
0714: return 0;
0715: }
0716:
0717: return flatProfileContainer.getNRows();
0718: }
0719:
0720: public int getColumnCount() {
0721: return columnCount;
0722: }
0723:
0724: @Override
0725: public Class getColumnClass(int col) {
0726: if (col == 1) {
0727: return Number.class;
0728: }
0729:
0730: return String.class;
0731: }
0732:
0733: public Object getValueAt(int row, int col) {
0734: switch (col) {
0735: case 0:
0736: return flatProfileContainer
0737: .getMethodNameAtRow(row);
0738: case 1:
0739: return new Float(flatProfileContainer
0740: .getPercentAtRow(row));
0741: case 2:
0742: return StringUtils
0743: .mcsTimeToString(flatProfileContainer
0744: .getTimeInMcs0AtRow(row))
0745: + " ms (" // NOI18N
0746: + percentFormat
0747: .format(flatProfileContainer
0748: .getPercentAtRow(row) / 100)
0749: + ")"; // NOI18N
0750: case 3:
0751: return collectingTwoTimeStamps ? (StringUtils
0752: .mcsTimeToString(flatProfileContainer
0753: .getTimeInMcs1AtRow(row)) + " ms" // NOI18N
0754: )
0755: : Integer
0756: .toString(flatProfileContainer
0757: .getNInvocationsAtRow(row));
0758: case 4:
0759: return Integer
0760: .toString(flatProfileContainer
0761: .getNInvocationsAtRow(row));
0762: default:
0763: return null;
0764: }
0765: }
0766:
0767: @Override
0768: public String getColumnToolTipText(int col) {
0769: return columnToolTips[col];
0770: }
0771:
0772: @Override
0773: public void sortByColumn(int column, boolean order) {
0774: sortingColumn = column;
0775: sortBy = getSortBy(column);
0776: sortOrder = order;
0777:
0778: int selectedRow = resTable.getSelectedRow();
0779: String selectedRowContents = null;
0780:
0781: if (selectedRow != -1) {
0782: selectedRowContents = (String) resTable
0783: .getValueAt(selectedRow, 0);
0784: }
0785:
0786: updateResults();
0787:
0788: if (selectedRowContents != null) {
0789: resTable.selectRowByContents(
0790: selectedRowContents, 0, true);
0791: }
0792: }
0793:
0794: /**
0795: * @param column The table column index
0796: * @return Initial sorting for the specified column - if true, ascending, if false descending
0797: */
0798: @Override
0799: public boolean getInitialSorting(int column) {
0800: switch (column) {
0801: case 0:
0802: return true;
0803: default:
0804: return false;
0805: }
0806: }
0807: });
0808:
0809: if (columnsVisibility != null) {
0810: resTableModel.setColumnsVisibility(columnsVisibility);
0811: }
0812:
0813: resTable = new JExtendedTable(resTableModel) {
0814: @Override
0815: public void doLayout() {
0816: int columnsWidthsSum = 0;
0817: int realFirstColumn = -1;
0818: int index;
0819:
0820: for (int i = 0; i < resTableModel.getColumnCount(); i++) {
0821: index = resTableModel.getRealColumn(i);
0822:
0823: if (index == 0) {
0824: realFirstColumn = i;
0825: } else {
0826: columnsWidthsSum += getColumnModel().getColumn(
0827: i).getPreferredWidth();
0828: }
0829: }
0830:
0831: if (realFirstColumn != -1) {
0832: getColumnModel().getColumn(realFirstColumn)
0833: .setPreferredWidth(
0834: Math.max(getWidth()
0835: - columnsWidthsSum,
0836: minNamesColumnWidth));
0837: }
0838:
0839: super .doLayout();
0840: }
0841:
0842: {
0843: }
0844: };
0845: resTable.getAccessibleContext().setAccessibleName(
0846: TABLE_ACCESS_NAME);
0847:
0848: resTableModel.setTable(resTable);
0849: resTableModel.setInitialSorting(sortingColumn, sortOrder);
0850: resTable.setRowSelectionAllowed(true);
0851: resTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0852: resTable.setGridColor(UIConstants.TABLE_VERTICAL_GRID_COLOR);
0853: resTable
0854: .setSelectionBackground(UIConstants.TABLE_SELECTION_BACKGROUND_COLOR);
0855: resTable
0856: .setSelectionForeground(UIConstants.TABLE_SELECTION_FOREGROUND_COLOR);
0857: resTable
0858: .setShowHorizontalLines(UIConstants.SHOW_TABLE_HORIZONTAL_GRID);
0859: resTable
0860: .setShowVerticalLines(UIConstants.SHOW_TABLE_VERTICAL_GRID);
0861: resTable.setRowMargin(UIConstants.TABLE_ROW_MARGIN);
0862: resTable.setRowHeight(UIUtils.getDefaultRowHeight() + 2);
0863: resTable.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
0864: .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
0865: "DEFAULT_ACTION"); // NOI18N
0866: resTable.getActionMap().put("DEFAULT_ACTION",
0867: new AbstractAction() {
0868: public void actionPerformed(ActionEvent e) {
0869: performDefaultAction();
0870: }
0871: }); // NOI18N
0872:
0873: // Disable traversing table cells using TAB and Shift+TAB
0874: Set keys = new HashSet(
0875: resTable
0876: .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
0877: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
0878: resTable.setFocusTraversalKeys(
0879: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
0880:
0881: keys = new HashSet(
0882: resTable
0883: .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
0884: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0885: InputEvent.SHIFT_MASK));
0886: resTable.setFocusTraversalKeys(
0887: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, keys);
0888:
0889: setColumnsData();
0890:
0891: // -------------------------------------
0892: resTable.getSelectionModel().addListSelectionListener(
0893: new ListSelectionListener() {
0894: private int lastSelection = -1;
0895:
0896: public void valueChanged(ListSelectionEvent e) {
0897: int selectedRow = resTable.getSelectedRow();
0898: methodId = (selectedRow != -1) ? flatProfileContainer
0899: .getMethodIdAtRow(selectedRow)
0900: : (-1);
0901:
0902: if (selectionHandler != null) {
0903: selectionHandler.methodSelected(
0904: lastSelection, methodId,
0905: currentView);
0906: }
0907:
0908: lastSelection = methodId;
0909: }
0910: });
0911:
0912: resTable.addKeyListener(new KeyAdapter() {
0913: @Override
0914: public void keyPressed(KeyEvent e) {
0915: if ((e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU)
0916: || ((e.getKeyCode() == KeyEvent.VK_F10) && (e
0917: .getModifiers() == InputEvent.SHIFT_MASK))) {
0918: int selectedRow = resTable.getSelectedRow();
0919:
0920: if (selectedRow != -1) {
0921: popupShowSource.setVisible(true);
0922:
0923: if (popupShowReverse != null) {
0924: popupShowReverse.setVisible(true);
0925: }
0926:
0927: popupPath = null;
0928: methodId = flatProfileContainer
0929: .getMethodIdAtRow(selectedRow);
0930: popupAddToRoots.setVisible(true);
0931:
0932: Rectangle cellRect = resTable.getCellRect(
0933: selectedRow, 0, false);
0934:
0935: callGraphPopupMenu
0936: .show(
0937: e.getComponent(),
0938: ((cellRect.x + resTable
0939: .getSize().width) > 50) ? 50
0940: : 5, cellRect.y);
0941: }
0942: }
0943: }
0944: });
0945:
0946: resTable.addMouseListener(new MouseAdapter() {
0947: @Override
0948: public void mousePressed(MouseEvent e) {
0949: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
0950: int line = resTable.rowAtPoint(e.getPoint());
0951:
0952: if (line != -1) {
0953: resTable.setRowSelectionInterval(line, line);
0954: }
0955: }
0956: }
0957:
0958: @Override
0959: public void mouseClicked(MouseEvent e) {
0960: int line = resTable.rowAtPoint(e.getPoint());
0961:
0962: if (line == -1) {
0963: popupShowSource.setVisible(false);
0964:
0965: if (popupShowReverse != null) {
0966: popupShowReverse.setVisible(false);
0967: }
0968:
0969: popupAddToRoots.setVisible(false);
0970:
0971: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
0972: popupPath = null;
0973: callGraphPopupMenu.show(e.getComponent(), e
0974: .getX(), e.getY());
0975: }
0976: } else {
0977: popupShowSource.setVisible(true);
0978:
0979: if (popupShowReverse != null) {
0980: popupShowReverse.setVisible(true);
0981: }
0982:
0983: popupAddToRoots.setVisible(true);
0984: methodId = flatProfileContainer
0985: .getMethodIdAtRow(line);
0986:
0987: if (e.getModifiers() == InputEvent.BUTTON3_MASK) {
0988: popupPath = null;
0989: callGraphPopupMenu.show(e.getComponent(), e
0990: .getX(), e.getY());
0991: } else if ((e.getModifiers() == InputEvent.BUTTON1_MASK)
0992: && (e.getClickCount() == 2)) {
0993: showSourceForMethod(methodId);
0994: }
0995: }
0996: }
0997: });
0998: noDataPanel = new JPanel(new BorderLayout());
0999: noDataPanel.add(new JLabel("No relevant data available"),
1000: BorderLayout.NORTH);
1001: noDataPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5,
1002: 5));
1003: noDataPanel.setBackground(resTable.getBackground());
1004: jScrollPane.setViewportView(null);
1005: // jScrollPane.setViewportView(resTable);
1006: jScrollPane.getViewport().setBackground(
1007: resTable.getBackground());
1008: }
1009:
1010: private void initFilterPanel() {
1011: filterComponent = new FilterComponent();
1012:
1013: //filterComponent.setEmptyFilterText("[Method Name Filter]");
1014: filterComponent
1015: .addFilterItem(
1016: new ImageIcon(
1017: filterComponent
1018: .getClass()
1019: .getResource(
1020: "/org/netbeans/lib/profiler/ui/resources/filterStartsWith.png") // NOI18N
1021: ), STARTS_WITH_STRING,
1022: CommonConstants.FILTER_STARTS_WITH);
1023: filterComponent
1024: .addFilterItem(
1025: new ImageIcon(
1026: filterComponent
1027: .getClass()
1028: .getResource(
1029: "/org/netbeans/lib/profiler/ui/resources/filterContains.png") // NOI18N
1030: ), CONTAINS_STRING,
1031: CommonConstants.FILTER_CONTAINS);
1032: filterComponent
1033: .addFilterItem(
1034: new ImageIcon(
1035: filterComponent
1036: .getClass()
1037: .getResource(
1038: "/org/netbeans/lib/profiler/ui/resources/filterEndsWith.png") // NOI18N
1039: ), ENDS_WITH_STRING,
1040: CommonConstants.FILTER_ENDS_WITH);
1041: filterComponent
1042: .addFilterItem(
1043: new ImageIcon(
1044: filterComponent
1045: .getClass()
1046: .getResource(
1047: "/org/netbeans/lib/profiler/ui/resources/filterRegExp.png")), // NOI18N
1048: REGEXP_STRING, CommonConstants.FILTER_REGEXP);
1049: //filterComponent.addSeparatorItem();
1050: filterComponent.setFilterValues(filterString, filterType);
1051:
1052: filterComponent
1053: .addFilterListener(new FilterComponent.FilterListener() {
1054: public void filterChanged() {
1055: String selectedRowContents = null;
1056:
1057: if (resTable != null) {
1058: int selectedRow = resTable.getSelectedRow();
1059:
1060: if (selectedRow != -1) {
1061: selectedRowContents = (String) resTable
1062: .getValueAt(selectedRow, 0);
1063: }
1064: }
1065:
1066: filterString = filterComponent
1067: .getFilterString();
1068: filterType = filterComponent.getFilterType();
1069:
1070: if (flatProfileContainer != null) { // can be null after reset, see Issue 65866
1071: flatProfileContainer
1072: .filterOriginalData(
1073: FilterComponent
1074: .getFilterStrings(filterString),
1075: filterType,
1076: valueFilterValue);
1077: flatProfileContainer.sortBy(sortBy,
1078: sortOrder);
1079: }
1080:
1081: if (resTable != null) { // can be null after reset, see Issue 65866
1082: resTable.invalidate();
1083: jScrollPane.revalidate();
1084: resTable.repaint();
1085:
1086: if (selectedRowContents != null) {
1087: resTable.selectRowByContents(
1088: selectedRowContents, 0, true);
1089: }
1090: }
1091: }
1092: });
1093:
1094: add(filterComponent, BorderLayout.SOUTH);
1095: }
1096:
1097: private void initFirstColumnName() {
1098: switch (currentView) {
1099: case CPUResultsSnapshot.METHOD_LEVEL_VIEW:
1100: columnNames[0] = METHOD_COLUMN_NAME;
1101: columnToolTips[0] = METHOD_COLUMN_TOOLTIP;
1102: filterComponent.setEmptyFilterText(METHOD_FILTER_HINT);
1103:
1104: break;
1105: case CPUResultsSnapshot.CLASS_LEVEL_VIEW:
1106: columnNames[0] = CLASS_COLUMN_NAME;
1107: columnToolTips[0] = CLASS_COLUMN_TOOLTIP;
1108: filterComponent.setEmptyFilterText(CLASS_FILTER_HINT);
1109:
1110: break;
1111: case CPUResultsSnapshot.PACKAGE_LEVEL_VIEW:
1112: columnNames[0] = PACKAGE_COLUMN_NAME;
1113: columnToolTips[0] = PACKAGE_COLUMN_TOOLTIP;
1114: filterComponent.setEmptyFilterText(PACKAGE_FILTER_HINT);
1115:
1116: break;
1117: }
1118:
1119: if (resTable != null) {
1120: resTable.getTableHeader().repaint();
1121: }
1122: }
1123: }
|