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.threads;
0042:
0043: import org.netbeans.lib.profiler.global.CommonConstants;
0044: import org.netbeans.lib.profiler.results.DataManagerListener;
0045: import org.netbeans.lib.profiler.results.threads.ThreadData;
0046: import org.netbeans.lib.profiler.results.threads.ThreadsDataManager;
0047: import org.netbeans.lib.profiler.ui.UIConstants;
0048: import org.netbeans.lib.profiler.ui.UIUtils;
0049: import org.netbeans.lib.profiler.ui.components.CellTipManager;
0050: import org.netbeans.lib.profiler.ui.components.FlatToolBar;
0051: import org.netbeans.lib.profiler.ui.components.JExtendedTable;
0052: import org.netbeans.lib.profiler.ui.components.table.LabelTableCellRenderer;
0053: import java.awt.*;
0054: import java.awt.event.*;
0055: import java.awt.image.BufferedImage;
0056: import java.util.ArrayList;
0057: import java.util.HashSet;
0058: import java.util.ResourceBundle;
0059: import java.util.Set;
0060: import javax.swing.*;
0061: import javax.swing.border.Border;
0062: import javax.swing.border.CompoundBorder;
0063: import javax.swing.event.ChangeEvent;
0064: import javax.swing.event.ListSelectionEvent;
0065: import javax.swing.event.TableColumnModelEvent;
0066: import javax.swing.event.TableColumnModelListener;
0067: import javax.swing.table.AbstractTableModel;
0068: import javax.swing.table.DefaultTableCellRenderer;
0069: import javax.swing.table.TableColumnModel;
0070:
0071: /**
0072: * A panel to display TA threads and their state.
0073: *
0074: * @author Ian Formanek
0075: * @author Jiri Sedlacek
0076: */
0077: public class ThreadsPanel extends JPanel implements AdjustmentListener,
0078: ActionListener, TableColumnModelListener, DataManagerListener {
0079: //~ Inner Interfaces ---------------------------------------------------------------------------------------------------------
0080:
0081: /** A callback interface - implemented by provider of additional details of a set of threads */
0082: public interface ThreadsDetailsCallback {
0083: //~ Methods --------------------------------------------------------------------------------------------------------------
0084:
0085: /** Displays a panel with details about specified threads
0086: *
0087: * @param indexes array of int indexes for threads to display
0088: */
0089: public void showDetails(int[] indexes);
0090: }
0091:
0092: //~ Inner Classes ------------------------------------------------------------------------------------------------------------
0093:
0094: class ThreadsScrollBar extends JScrollBar {
0095: //~ Constructors ---------------------------------------------------------------------------------------------------------
0096:
0097: public ThreadsScrollBar() {
0098: super (JScrollBar.HORIZONTAL);
0099: }
0100:
0101: //~ Methods --------------------------------------------------------------------------------------------------------------
0102:
0103: public Dimension getPreferredSize() {
0104: Dimension pref = super .getPreferredSize();
0105:
0106: return new Dimension(table.getTableHeader().getHeaderRect(
0107: DISPLAY_COLUMN_INDEX).width, pref.height);
0108: }
0109: }
0110:
0111: // ---------------------------------------------------------------------------------------
0112: // Model for the table
0113: private class ThreadsTableModel extends AbstractTableModel {
0114: //~ Methods --------------------------------------------------------------------------------------------------------------
0115:
0116: public Class getColumnClass(int column) {
0117: // The main purpose of this method is to make numeric values aligned properly inside table cells
0118: switch (column) {
0119: case NAME_COLUMN_INDEX:
0120: return ThreadNameCellRenderer.class;
0121: case DISPLAY_COLUMN_INDEX:
0122: return ThreadStateCellRenderer.class;
0123: default:
0124: return String.class;
0125: }
0126: }
0127:
0128: public int getColumnCount() {
0129: return 2;
0130: }
0131:
0132: /**
0133: * Returns a default name for the column using spreadsheet conventions:
0134: * A, B, C, ... Z, AA, AB, etc. If <code>column</code> cannot be found,
0135: * returns an empty string.
0136: *
0137: * @param column the column being queried
0138: * @return a string containing the default name of <code>column</code>
0139: */
0140: public String getColumnName(int column) {
0141: switch (column) {
0142: case NAME_COLUMN_INDEX:
0143: return THREADS_COLUMN_NAME;
0144: case DISPLAY_COLUMN_INDEX:
0145: return TIMELINE_COLUMN_NAME;
0146: default:
0147: return null;
0148: }
0149: }
0150:
0151: public int getRowCount() {
0152: //return manager.getThreadsCount();
0153: return filteredDataToDataIndex.size();
0154: }
0155:
0156: public Object getValueAt(int rowIndex, int columnIndex) {
0157: switch (columnIndex) {
0158: case NAME_COLUMN_INDEX:
0159: return (Integer) (filteredDataToDataIndex.get(rowIndex));
0160: case DISPLAY_COLUMN_INDEX:
0161: return getThreadData(((Integer) (filteredDataToDataIndex
0162: .get(rowIndex))).intValue());
0163: default:
0164: return null;
0165: }
0166: }
0167: }
0168:
0169: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
0170:
0171: // -----
0172: // I18N String constants
0173: private static final ResourceBundle messages = ResourceBundle
0174: .getBundle("org.netbeans.lib.profiler.ui.threads.Bundle"); // NOI18N
0175: private static final String VIEW_THREADS_ALL = messages
0176: .getString("ThreadsPanel_ViewThreadsAll"); // NOI18N
0177: private static final String VIEW_THREADS_LIVE = messages
0178: .getString("ThreadsPanel_ViewThreadsLive"); // NOI18N
0179: private static final String VIEW_THREADS_FINISHED = messages
0180: .getString("ThreadsPanel_ViewThreadsFinished"); // NOI18N
0181: private static final String VIEW_THREADS_SELECTION = messages
0182: .getString("ThreadsPanel_ViewThreadsSelection"); // NOI18N
0183: private static final String THREADS_TABLE = messages
0184: .getString("ThreadsPanel_ThreadsTable"); // NOI18N
0185: private static final String ENABLE_THREADS_PROFILING = messages
0186: .getString("ThreadsPanel_EnableThreadsProfiling"); // NOI18N
0187: private static final String ZOOM_IN_TOOLTIP = messages
0188: .getString("ThreadsPanel_ZoomInToolTip"); // NOI18N
0189: private static final String ZOOM_OUT_TOOLTIP = messages
0190: .getString("ThreadsPanel_ZoomOutToolTip"); // NOI18N
0191: private static final String FIXED_SCALE_TOOLTIP = messages
0192: .getString("ThreadsPanel_FixedScaleToolTip"); // NOI18N
0193: private static final String SCALE_TO_FIT_TOOLTIP = messages
0194: .getString("ThreadsPanel_ScaleToFitToolTip"); // NOI18N
0195: private static final String THREADS_MONITORING_DISABLED_1_MSG = messages
0196: .getString("ThreadsPanel_ThreadsMonitoringDisabled1Msg"); // NOI18N
0197: private static final String THREADS_MONITORING_DISABLED_2_MSG = messages
0198: .getString("ThreadsPanel_ThreadsMonitoringDisabled2Msg"); // NOI18N
0199: private static final String NO_PROFILING_MSG = messages
0200: .getString("ThreadsPanel_NoProfilingMsg"); // NOI18N
0201: private static final String THREADS_COLUMN_NAME = messages
0202: .getString("ThreadsPanel_ThreadsColumnName"); // NOI18N
0203: private static final String TIMELINE_COLUMN_NAME = messages
0204: .getString("ThreadsPanel_TimelineColumnName"); // NOI18N
0205: private static final String SELECTED_THREADS_ITEM = messages
0206: .getString("ThreadsPanel_SelectedThreadsItem"); // NOI18N
0207: private static final String THREAD_DETAILS_ITEM = messages
0208: .getString("ThreadsPanel_ThreadDetailsItem"); // NOI18N
0209: private static final String TABLE_ACCESS_NAME = messages
0210: .getString("ThreadsPanel_TableAccessName"); // NOI18N
0211: private static final String TABLE_ACCESS_DESCR = messages
0212: .getString("ThreadsPanel_TableAccessDescr"); // NOI18N
0213: private static final String COMBO_ACCESS_NAME = messages
0214: .getString("ThreadsPanel_ComboAccessName"); // NOI18N
0215: private static final String COMBO_ACCESS_DESCR = messages
0216: .getString("ThreadsPanel_ComboAccessDescr"); // NOI18N
0217: private static final String ENABLE_THREADS_MONITORING_BUTTON_ACCESS_NAME = messages
0218: .getString("ThreadsPanel_EnableThreadsMonitoringAccessName"); // NOI18N
0219: private static final String SHOW_LABEL_TEXT = messages
0220: .getString("ThreadsPanel_ShowLabelText"); // NOI18N
0221: // -----
0222: private static final int NAME_COLUMN_INDEX = 0;
0223: private static final int DISPLAY_COLUMN_INDEX = 1;
0224: private static final int RIGHT_DISPLAY_MARGIN = 20; // extra space [pixels] on the right end of the threads display
0225: private static final int LEFT_DISPLAY_MARGIN = 20;
0226: private static final int NAME_COLUMN_WIDTH = 190;
0227: private static final int MIN_NAME_COLUMN_WIDTH = 55;
0228:
0229: //~ Instance fields ----------------------------------------------------------------------------------------------------------
0230:
0231: private ArrayList filteredDataToDataIndex = new ArrayList();
0232: private CustomTimeLineViewport viewPort;
0233: private DefaultComboBoxModel comboModel;
0234: private DefaultComboBoxModel comboModelWithSelection;
0235: private JButton enableThreadsMonitoringButton;
0236: private JButton scaleToFitButton;
0237: private JButton zoomInButton;
0238: private JButton zoomOutButton;
0239: private JComboBox threadsSelectionCombo;
0240: private JLabel enableThreadsMonitoringLabel1;
0241: private JLabel enableThreadsMonitoringLabel2;
0242: private JLabel enableThreadsMonitoringLabel3;
0243: private JLabel monitorLegend;
0244: private JLabel runningLegend;
0245: private JLabel sleepingLegend;
0246: private JLabel waitLegend;
0247: private JMenuItem showOnlySelectedThreads;
0248: private JMenuItem showThreadsDetails;
0249: private JPanel contentPanel; // panel with CardLayout containing threadsTable & enable threads profiling notification and button
0250: private JPanel notificationPanel;
0251: private JPopupMenu popupMenu;
0252: private JScrollBar scrollBar; // scrollbar that is displayed in zoomed mode that allows to scroll in history
0253: private JScrollPane tableScroll;
0254: private JTable table; // table that displays individual threads
0255: private JToolBar buttonsToolBar;
0256: private ThreadsDataManager manager;
0257: private ThreadsDetailsCallback detailsCallback;
0258: private boolean internalChange = false; // prevents cycles in event handling
0259: private boolean internalScrollbarChange = false;
0260: private boolean resetPerformed = true;
0261: private boolean scaleToFit = false;
0262: private boolean supportsSleepingState; // internal flag indicating that threads monitoring engine correctly reports the "sleeping" state
0263: private boolean threadsMonitoringEnabled = false;
0264: private boolean trackingEnd = true;
0265: private float zoomResolutionPerPixel = 50f;
0266: private long viewEnd;
0267: private long viewStart = -1;
0268:
0269: //~ Constructors -------------------------------------------------------------------------------------------------------------
0270:
0271: /**
0272: * Creates a new threads panel that displays threads timeline from data provided
0273: * by specified ThreadsDataManager.
0274: * @param manager The provider of threads data
0275: * @param detailsCallback A handler of displaying additional threads details or null, in which case the
0276: * popup menu action to display details will not be present
0277: */
0278: public ThreadsPanel(ThreadsDataManager manager,
0279: ThreadsDetailsCallback detailsCallback,
0280: boolean supportsSleepingState) {
0281: this .manager = manager;
0282: this .detailsCallback = detailsCallback;
0283: this .supportsSleepingState = supportsSleepingState;
0284:
0285: // create components
0286:
0287: // contentPanel for threadsTable and enable threads profiling notification
0288: contentPanel = new JPanel(new CardLayout());
0289:
0290: // threads table components
0291: table = createViewTable();
0292: table.setGridColor(UIConstants.TABLE_VERTICAL_GRID_COLOR);
0293: table.getAccessibleContext().setAccessibleName(
0294: TABLE_ACCESS_NAME);
0295: table.getAccessibleContext().setAccessibleDescription(
0296: TABLE_ACCESS_DESCR);
0297: table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
0298: .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
0299: "DEFAULT_ACTION"); // NOI18N
0300: table.getActionMap().put("DEFAULT_ACTION",
0301: new AbstractAction() {
0302: public void actionPerformed(ActionEvent e) {
0303: performDefaultAction();
0304: }
0305: }); // NOI18N
0306:
0307: scrollBar = new ThreadsScrollBar();
0308: zoomInButton = new JButton(
0309: new ImageIcon(
0310: ThreadsPanel.class
0311: .getResource("/org/netbeans/lib/profiler/ui/resources/zoomIn.png"))); // NOI18N
0312: zoomOutButton = new JButton(
0313: new ImageIcon(
0314: ThreadsPanel.class
0315: .getResource("/org/netbeans/lib/profiler/ui/resources/zoomOut.png"))); // NOI18N
0316: scaleToFitButton = new JButton(
0317: new ImageIcon(
0318: getClass()
0319: .getResource(
0320: scaleToFit ? "/org/netbeans/lib/profiler/ui/resources/zoom.png"
0321: : "/org/netbeans/lib/profiler/ui/resources/scaleToFit.png"))); // NOI18N
0322: comboModel = new DefaultComboBoxModel(new Object[] {
0323: VIEW_THREADS_ALL, VIEW_THREADS_LIVE,
0324: VIEW_THREADS_FINISHED });
0325: comboModelWithSelection = new DefaultComboBoxModel(
0326: new Object[] { VIEW_THREADS_ALL, VIEW_THREADS_LIVE,
0327: VIEW_THREADS_FINISHED, VIEW_THREADS_SELECTION });
0328: threadsSelectionCombo = new JComboBox(comboModel) {
0329: public Dimension getMaximumSize() {
0330: return new Dimension(250, getPreferredSize().height);
0331: };
0332: };
0333: threadsSelectionCombo.getAccessibleContext().setAccessibleName(
0334: COMBO_ACCESS_NAME);
0335: threadsSelectionCombo.getAccessibleContext()
0336: .setAccessibleDescription(COMBO_ACCESS_DESCR);
0337:
0338: JLabel showLabel = new JLabel(SHOW_LABEL_TEXT);
0339: showLabel
0340: .setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
0341: showLabel.setLabelFor(threadsSelectionCombo);
0342:
0343: int mnemCharIndex = 0;
0344: showLabel.setDisplayedMnemonic(showLabel.getText().charAt(
0345: mnemCharIndex));
0346: showLabel.setDisplayedMnemonicIndex(mnemCharIndex);
0347:
0348: buttonsToolBar = new JToolBar(JToolBar.HORIZONTAL) {
0349: public Component add(Component comp) {
0350: if (comp instanceof JButton) {
0351: UIUtils.fixButtonUI((JButton) comp);
0352: }
0353:
0354: return super .add(comp);
0355: }
0356: };
0357:
0358: JPanel tablePanel = new JPanel();
0359: JPanel scrollPanel = new JPanel();
0360: popupMenu = initPopupMenu();
0361:
0362: // set properties
0363: zoomInButton.setEnabled(!scaleToFit);
0364: zoomOutButton.setEnabled(!scaleToFit);
0365: zoomInButton.setToolTipText(ZOOM_IN_TOOLTIP);
0366: zoomOutButton.setToolTipText(ZOOM_OUT_TOOLTIP);
0367: scaleToFitButton
0368: .setToolTipText(scaleToFit ? FIXED_SCALE_TOOLTIP
0369: : SCALE_TO_FIT_TOOLTIP);
0370: zoomInButton.getAccessibleContext().setAccessibleName(
0371: zoomInButton.getToolTipText());
0372: zoomOutButton.getAccessibleContext().setAccessibleName(
0373: zoomOutButton.getToolTipText());
0374: scaleToFitButton.getAccessibleContext().setAccessibleName(
0375: scaleToFitButton.getToolTipText());
0376:
0377: table
0378: .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0379: table
0380: .setSelectionBackground(UIConstants.TABLE_SELECTION_BACKGROUND_COLOR);
0381: table
0382: .setSelectionForeground(UIConstants.TABLE_SELECTION_FOREGROUND_COLOR);
0383: table.setShowGrid(false);
0384: table.setRowMargin(0);
0385: table.setRowHeight(23);
0386:
0387: DefaultTableCellRenderer defaultHeaderRenderer = new DefaultTableCellRenderer() {
0388: public Component getTableCellRendererComponent(
0389: JTable table, Object value, boolean isSelected,
0390: boolean hasFocus, int row, int column) {
0391: Component component = super
0392: .getTableCellRendererComponent(table, value,
0393: isSelected, hasFocus, row, column);
0394: component.setBackground(Color.WHITE);
0395: component
0396: .setFont(table.getFont().deriveFont(Font.BOLD));
0397:
0398: if (component instanceof JComponent) {
0399: ((JComponent) component)
0400: .setBorder(new javax.swing.border.EmptyBorder(
0401: 0, 3, 0, 3));
0402: }
0403:
0404: return component;
0405: }
0406: };
0407:
0408: table.getTableHeader()
0409: .setDefaultRenderer(defaultHeaderRenderer);
0410: table.getTableHeader().setReorderingAllowed(false);
0411:
0412: // fix the first column's width, and make the display column resize
0413: table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
0414: table.getColumnModel().getColumn(NAME_COLUMN_INDEX)
0415: .setMinWidth(MIN_NAME_COLUMN_WIDTH);
0416: table.getColumnModel().getColumn(NAME_COLUMN_INDEX)
0417: .setMaxWidth(1000); // this is for some reason needed for the width to actually work
0418: table.getColumnModel().getColumn(NAME_COLUMN_INDEX)
0419: .setPreferredWidth(NAME_COLUMN_WIDTH);
0420:
0421: ThreadStateHeaderRenderer headerRenderer = new ThreadStateHeaderRenderer(
0422: this );
0423: headerRenderer.setBackground(Color.WHITE);
0424: table.getColumnModel().getColumn(DISPLAY_COLUMN_INDEX)
0425: .setHeaderRenderer(headerRenderer);
0426:
0427: TableColumnModel columnModel = table.getColumnModel();
0428: columnModel.setColumnSelectionAllowed(false);
0429: columnModel.setColumnMargin(0);
0430: table.setDefaultRenderer(ThreadNameCellRenderer.class,
0431: new ThreadNameCellRenderer(this ));
0432: table.setDefaultRenderer(ThreadStateCellRenderer.class,
0433: new ThreadStateCellRenderer(this ));
0434: buttonsToolBar.setFloatable(false);
0435: buttonsToolBar.putClientProperty("JToolBar.isRollover",
0436: Boolean.TRUE); // NOI18N
0437:
0438: // perform layout
0439: tablePanel.setLayout(new BorderLayout());
0440: scrollPanel.setLayout(new BorderLayout());
0441: scrollPanel.setBackground(Color.WHITE);
0442:
0443: buttonsToolBar.add(zoomInButton);
0444: buttonsToolBar.add(zoomOutButton);
0445: buttonsToolBar.add(scaleToFitButton);
0446: buttonsToolBar.addSeparator();
0447: buttonsToolBar.add(showLabel);
0448: buttonsToolBar.add(threadsSelectionCombo);
0449: scrollPanel.add(scrollBar, BorderLayout.EAST);
0450:
0451: //
0452: ThreadStateIcon runningIcon = new ThreadStateIcon(
0453: CommonConstants.THREAD_STATUS_RUNNING, 18, 9);
0454: ThreadStateIcon sleepingIcon = new ThreadStateIcon(
0455: CommonConstants.THREAD_STATUS_SLEEPING, 18, 9);
0456: ThreadStateIcon monitorIcon = new ThreadStateIcon(
0457: CommonConstants.THREAD_STATUS_MONITOR, 18, 9);
0458: ThreadStateIcon waitIcon = new ThreadStateIcon(
0459: CommonConstants.THREAD_STATUS_WAIT, 18, 9);
0460:
0461: runningLegend = new JLabel(
0462: CommonConstants.THREAD_STATUS_RUNNING_STRING,
0463: runningIcon, SwingConstants.LEADING);
0464: runningLegend.setBorder(BorderFactory.createEmptyBorder(0, 5,
0465: 0, 0));
0466: sleepingLegend = new JLabel(
0467: CommonConstants.THREAD_STATUS_SLEEPING_STRING,
0468: sleepingIcon, SwingConstants.LEADING);
0469: sleepingLegend.setBorder(BorderFactory.createEmptyBorder(0, 5,
0470: 0, 0));
0471: waitLegend = new JLabel(
0472: CommonConstants.THREAD_STATUS_WAIT_STRING, waitIcon,
0473: SwingConstants.LEADING);
0474: waitLegend.setBorder(BorderFactory
0475: .createEmptyBorder(0, 5, 0, 0));
0476: monitorLegend = new JLabel(
0477: CommonConstants.THREAD_STATUS_MONITOR_STRING,
0478: monitorIcon, SwingConstants.LEADING);
0479: monitorLegend.setBorder(BorderFactory.createEmptyBorder(0, 5,
0480: 0, 0));
0481:
0482: JPanel legendPanel = new JPanel();
0483: legendPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0,
0484: 0));
0485: legendPanel.add(runningLegend);
0486: legendPanel.add(sleepingLegend);
0487:
0488: if (!supportsSleepingState) {
0489: sleepingLegend.setVisible(false);
0490: }
0491:
0492: legendPanel.add(waitLegend);
0493: legendPanel.add(monitorLegend);
0494:
0495: //legendPanel.add(unknownLegend);
0496: JPanel bottomPanel = new JPanel();
0497: bottomPanel.setLayout(new BorderLayout());
0498: bottomPanel.add(legendPanel, BorderLayout.EAST);
0499:
0500: //scrollPanel.add(bottomPanel, BorderLayout.SOUTH);
0501: JPanel dataPanel = new JPanel();
0502: dataPanel.setLayout(new BorderLayout());
0503: dataPanel
0504: .setBorder(BorderFactory
0505: .createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
0506:
0507: tableScroll = new JScrollPane();
0508: tableScroll.setBorder(new javax.swing.border.EmptyBorder(0, 0,
0509: 0, 0));
0510: tableScroll.setCorner(JScrollPane.UPPER_RIGHT_CORNER,
0511: new JPanel());
0512: tableScroll.getCorner(JScrollPane.UPPER_RIGHT_CORNER)
0513: .setBackground(Color.WHITE);
0514: viewPort = new CustomTimeLineViewport(this );
0515: viewPort.setView(table);
0516: viewPort.setBackground(table.getBackground());
0517: tableScroll.setViewport(viewPort);
0518: tableScroll
0519: .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
0520: tableScroll
0521: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
0522: dataPanel.add(tableScroll, BorderLayout.CENTER);
0523: dataPanel.add(scrollPanel, BorderLayout.SOUTH);
0524: tablePanel.add(dataPanel, BorderLayout.CENTER);
0525: tablePanel.add(bottomPanel, BorderLayout.SOUTH);
0526:
0527: // enable threads profiling components
0528: notificationPanel = new JPanel(new FlowLayout(
0529: FlowLayout.LEADING, 0, 15));
0530: notificationPanel.setBorder(dataPanel.getBorder());
0531: notificationPanel.setBackground(table.getBackground());
0532:
0533: Border myRolloverBorder = new CompoundBorder(
0534: new FlatToolBar.FlatRolloverButtonBorder(Color.GRAY,
0535: Color.LIGHT_GRAY),
0536: new FlatToolBar.FlatMarginBorder());
0537:
0538: enableThreadsMonitoringLabel1 = new JLabel(
0539: THREADS_MONITORING_DISABLED_1_MSG);
0540: enableThreadsMonitoringLabel1.setBorder(BorderFactory
0541: .createEmptyBorder(20, 20, 20, 3));
0542: enableThreadsMonitoringLabel1.setForeground(Color.DARK_GRAY);
0543:
0544: enableThreadsMonitoringButton = new JButton(
0545: new ImageIcon(
0546: getClass()
0547: .getResource(
0548: "/org/netbeans/lib/profiler/ui/resources/threadsView.png"))); // NOI18N
0549: enableThreadsMonitoringButton.setContentAreaFilled(false);
0550: enableThreadsMonitoringButton.setMargin(new Insets(3, 3, 0, 0));
0551: enableThreadsMonitoringButton
0552: .setVerticalTextPosition(SwingConstants.BOTTOM);
0553: enableThreadsMonitoringButton
0554: .setHorizontalTextPosition(SwingConstants.CENTER);
0555: enableThreadsMonitoringButton.setRolloverEnabled(true);
0556: enableThreadsMonitoringButton.setBorder(myRolloverBorder);
0557: enableThreadsMonitoringButton.getAccessibleContext()
0558: .setAccessibleName(
0559: ENABLE_THREADS_MONITORING_BUTTON_ACCESS_NAME);
0560:
0561: enableThreadsMonitoringLabel2 = new JLabel(
0562: THREADS_MONITORING_DISABLED_2_MSG);
0563: enableThreadsMonitoringLabel2.setBorder(BorderFactory
0564: .createEmptyBorder(20, 3, 20, 0));
0565: enableThreadsMonitoringLabel2.setForeground(Color.DARK_GRAY);
0566:
0567: enableThreadsMonitoringLabel3 = new JLabel(NO_PROFILING_MSG);
0568: enableThreadsMonitoringLabel3.setBorder(BorderFactory
0569: .createEmptyBorder(20, 20, 20, 0));
0570: enableThreadsMonitoringLabel3.setForeground(Color.DARK_GRAY);
0571: enableThreadsMonitoringLabel3.setVisible(false);
0572:
0573: notificationPanel.add(enableThreadsMonitoringLabel1);
0574: notificationPanel.add(enableThreadsMonitoringButton);
0575: notificationPanel.add(enableThreadsMonitoringLabel2);
0576: notificationPanel.add(enableThreadsMonitoringLabel3);
0577:
0578: setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
0579: setLayout(new BorderLayout());
0580:
0581: contentPanel.add(notificationPanel, ENABLE_THREADS_PROFILING);
0582: contentPanel.add(tablePanel, THREADS_TABLE);
0583:
0584: add(buttonsToolBar, BorderLayout.NORTH);
0585: add(contentPanel, BorderLayout.CENTER);
0586:
0587: scrollBar.addAdjustmentListener(this );
0588: zoomInButton.addActionListener(this );
0589: zoomOutButton.addActionListener(this );
0590: scaleToFitButton.addActionListener(this );
0591: threadsSelectionCombo.addActionListener(this );
0592: showOnlySelectedThreads.addActionListener(this );
0593:
0594: if (detailsCallback != null) {
0595: showThreadsDetails.addActionListener(this );
0596: }
0597:
0598: table.getColumnModel().addColumnModelListener(this );
0599: table.addComponentListener(new ComponentAdapter() {
0600: public void componentResized(ComponentEvent e) {
0601: refreshViewData();
0602: updateScrollbar();
0603: updateZoomButtonsEnabledState();
0604: ThreadsPanel.this .revalidate();
0605: }
0606: });
0607:
0608: table.addKeyListener(new KeyAdapter() {
0609: public void keyPressed(KeyEvent e) {
0610: if ((e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU)
0611: || ((e.getKeyCode() == KeyEvent.VK_F10) && (e
0612: .getModifiers() == InputEvent.SHIFT_MASK))) {
0613: int selectedRow = table.getSelectedRow();
0614:
0615: if (selectedRow != -1) {
0616: Rectangle cellRect = table.getCellRect(
0617: selectedRow, 0, false);
0618: popupMenu
0619: .show(
0620: e.getComponent(),
0621: ((cellRect.x + table.getSize().width) > 50) ? 50
0622: : 5, cellRect.y);
0623: }
0624: }
0625: }
0626: });
0627:
0628: table.addMouseListener(new MouseAdapter() {
0629: public void mousePressed(MouseEvent e) {
0630: if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
0631: int line = table.rowAtPoint(e.getPoint());
0632:
0633: if ((line != -1) && (!table.isRowSelected(line))) {
0634: if (e.isControlDown()) {
0635: table.addRowSelectionInterval(line, line);
0636: } else {
0637: table.setRowSelectionInterval(line, line);
0638: }
0639: }
0640: }
0641: }
0642:
0643: public void mouseClicked(MouseEvent e) {
0644: int clickedLine = table.rowAtPoint(e.getPoint());
0645:
0646: if (clickedLine != -1) {
0647: if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
0648: popupMenu.show(e.getComponent(), e.getX(), e
0649: .getY());
0650: } else if ((e.getModifiers() == InputEvent.BUTTON1_MASK)
0651: && (e.getClickCount() == 2)) {
0652: performDefaultAction();
0653: }
0654: }
0655: }
0656: });
0657: addComponentListener(new ComponentAdapter() {
0658: public void componentShown(ComponentEvent e) {
0659: // since the data were not processed when this component was not showing,
0660: // we need to do the updateState when the component becomes visible
0661: dataChanged();
0662: }
0663: });
0664:
0665: // Disable traversing table cells using TAB and Shift+TAB
0666: Set keys = new HashSet(
0667: table
0668: .getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
0669: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
0670: table.setFocusTraversalKeys(
0671: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
0672:
0673: keys = new HashSet(
0674: table
0675: .getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
0676: keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0677: InputEvent.SHIFT_MASK));
0678: table.setFocusTraversalKeys(
0679: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, keys);
0680:
0681: updateScrollbar();
0682: updateZoomButtonsEnabledState();
0683: manager.addDataListener(this );
0684: }
0685:
0686: //~ Methods ------------------------------------------------------------------------------------------------------------------
0687:
0688: public BufferedImage getCurrentViewScreenshot(
0689: boolean onlyVisibleArea) {
0690: if (onlyVisibleArea) {
0691: return UIUtils.createScreenshot(tableScroll);
0692: } else {
0693: return UIUtils.createScreenshot(table);
0694: }
0695: }
0696:
0697: public long getDataEnd() {
0698: return manager.getEndTime();
0699: }
0700:
0701: public long getDataStart() {
0702: return manager.getStartTime();
0703: }
0704:
0705: public int getDisplayColumnWidth() {
0706: return table.getTableHeader().getHeaderRect(
0707: DISPLAY_COLUMN_INDEX).width;
0708: }
0709:
0710: public String getThreadClassName(int index) {
0711: return manager.getThreadClassName(index);
0712: }
0713:
0714: public ThreadData getThreadData(int index) {
0715: return manager.getThreadData(index);
0716: }
0717:
0718: // ---------------------------------------------------------------------------------------
0719: // Thread data
0720: public String getThreadName(int index) {
0721: return manager.getThreadName(index);
0722: }
0723:
0724: public long getViewEnd() {
0725: return viewEnd;
0726: }
0727:
0728: // ---------------------------------------------------------------------------------------
0729: // View controller
0730: public long getViewStart() {
0731: return viewStart;
0732: }
0733:
0734: /** Invoked when one of the buttons is pressed */
0735: public void actionPerformed(ActionEvent e) {
0736: if (internalChange) {
0737: return;
0738: }
0739:
0740: if (e.getSource() == scaleToFitButton) {
0741: if (!scaleToFit) {
0742: scrollBar.setVisible(true);
0743: scaleToFitButton
0744: .setIcon(new ImageIcon(
0745: ThreadsPanel.class
0746: .getResource("/org/netbeans/lib/profiler/ui/resources/zoom.png"))); // NOI18N
0747: scaleToFit = true;
0748: } else {
0749: scaleToFit = false;
0750: scaleToFitButton
0751: .setIcon(new ImageIcon(
0752: getClass()
0753: .getResource(
0754: "/org/netbeans/lib/profiler/ui/resources/scaleToFit.png"))); // NOI18N
0755: scrollBar.setVisible(false);
0756: scrollBar.setValues(0, 0, 0, 0);
0757: }
0758:
0759: refreshViewData();
0760: updateScrollbar();
0761: updateZoomButtonsEnabledState();
0762: table.getTableHeader().repaint();
0763: viewPort.repaint();
0764: } else if (e.getSource() == zoomInButton) {
0765: zoomInButton.setEnabled(zoomResolutionPerPixel > 0.1);
0766: zoomResolutionPerPixel /= 2;
0767: refreshViewData();
0768: updateScrollbar();
0769: updateZoomButtonsEnabledState();
0770: table.getTableHeader().repaint();
0771: viewPort.repaint();
0772: } else if (e.getSource() == zoomOutButton) {
0773: zoomResolutionPerPixel *= 2;
0774: refreshViewData();
0775: updateScrollbar();
0776: updateZoomButtonsEnabledState();
0777: table.getTableHeader().repaint();
0778: viewPort.repaint();
0779: } else if (e.getSource() == threadsSelectionCombo) {
0780: if ((threadsSelectionCombo.getModel() == comboModelWithSelection)
0781: && (threadsSelectionCombo.getSelectedItem() != VIEW_THREADS_SELECTION)) {
0782: internalChange = true;
0783:
0784: Object selectedItem = threadsSelectionCombo
0785: .getSelectedItem();
0786: threadsSelectionCombo.setModel(comboModel);
0787: threadsSelectionCombo.setSelectedItem(selectedItem);
0788: internalChange = false;
0789: }
0790:
0791: table.clearSelection();
0792: dataChanged();
0793: } else if (e.getSource() == showOnlySelectedThreads) {
0794: for (int i = filteredDataToDataIndex.size() - 1; i >= 0; i--) {
0795: if (!table.isRowSelected(i)) {
0796: filteredDataToDataIndex.remove(i);
0797: }
0798: }
0799:
0800: threadsSelectionCombo.setModel(comboModelWithSelection);
0801: threadsSelectionCombo
0802: .setSelectedItem(VIEW_THREADS_SELECTION);
0803: table.clearSelection();
0804: } else if (e.getSource() == showThreadsDetails) {
0805: performDefaultAction();
0806: }
0807: }
0808:
0809: // --- Save Current View action support --------------------------------------
0810: public void addSaveViewAction(AbstractAction saveViewAction) {
0811: JButton actionButton = buttonsToolBar.add(saveViewAction);
0812: buttonsToolBar.remove(actionButton);
0813:
0814: buttonsToolBar.add(actionButton, 0);
0815: buttonsToolBar.add(new JToolBar.Separator(), 1);
0816: }
0817:
0818: // ---------------------------------------------------------------------------------------
0819: // Handling profiling started & finished and threads monitoring enabled & disabled
0820: public void addThreadsMonitoringActionListener(
0821: ActionListener listener) {
0822: enableThreadsMonitoringButton.addActionListener(listener);
0823: }
0824:
0825: // ---------------------------------------------------------------------------------------
0826: // Listeners
0827:
0828: /**
0829: * Invoked when the scrollbar is moved.
0830: */
0831: public void adjustmentValueChanged(AdjustmentEvent e) {
0832: // we know we are in zoom mode (in scaleToFit, the scrollbar is disabled)
0833: if (!internalScrollbarChange) {
0834: if ((scrollBar.getValue() + scrollBar.getVisibleAmount()) == scrollBar
0835: .getMaximum()) {
0836: trackingEnd = true;
0837: } else {
0838: trackingEnd = false;
0839: viewStart = manager.getStartTime()
0840: + scrollBar.getValue();
0841: viewEnd = viewStart
0842: + (long) (zoomResolutionPerPixel * table
0843: .getTableHeader().getHeaderRect(
0844: DISPLAY_COLUMN_INDEX).width);
0845: ThreadsPanel.this .repaint();
0846: }
0847: }
0848: }
0849:
0850: public void columnAdded(TableColumnModelEvent e) {
0851: } // Ignored
0852:
0853: /**
0854: * Tells listeners that a column was moved due to a margin change.
0855: */
0856: public void columnMarginChanged(ChangeEvent e) {
0857: refreshViewData();
0858: updateScrollbar();
0859: updateZoomButtonsEnabledState();
0860:
0861: if (viewPort != null) {
0862: viewPort.repaint();
0863: }
0864:
0865: scrollBar.invalidate();
0866: ThreadsPanel.this .revalidate();
0867: }
0868:
0869: public void columnMoved(TableColumnModelEvent e) {
0870: } // Ignored
0871:
0872: public void columnRemoved(TableColumnModelEvent e) {
0873: } // Ignored
0874:
0875: public void columnSelectionChanged(ListSelectionEvent e) {
0876: } // Ignored
0877:
0878: /** Called when data in manager change */
0879: public void dataChanged() {
0880: UIUtils.runInEventDispatchThread(new Runnable() {
0881: public void run() {
0882: refreshUI();
0883: }
0884: });
0885: }
0886:
0887: public void dataReset() {
0888: filteredDataToDataIndex.clear();
0889: UIUtils.runInEventDispatchThread(new Runnable() {
0890: public void run() {
0891: refreshUI();
0892: updateSupportsSleepingState(manager
0893: .supportsSleepingStateMonitoring());
0894: }
0895: });
0896: }
0897:
0898: public boolean fitsVisibleArea() {
0899: return !tableScroll.getVerticalScrollBar().isVisible();
0900: }
0901:
0902: public boolean hasView() {
0903: return !notificationPanel.isShowing();
0904: }
0905:
0906: public void profilingSessionFinished() {
0907: enableThreadsMonitoringButton.setEnabled(false);
0908: enableThreadsMonitoringLabel1.setVisible(false);
0909: enableThreadsMonitoringLabel2.setVisible(false);
0910: enableThreadsMonitoringButton.setVisible(false);
0911: enableThreadsMonitoringLabel3.setVisible(true);
0912: }
0913:
0914: public void profilingSessionStarted() {
0915: enableThreadsMonitoringButton.setEnabled(true);
0916: enableThreadsMonitoringLabel1.setVisible(true);
0917: enableThreadsMonitoringLabel2.setVisible(true);
0918: enableThreadsMonitoringButton.setVisible(true);
0919: enableThreadsMonitoringLabel3.setVisible(false);
0920: }
0921:
0922: public void removeThreadsMonitoringActionListener(
0923: ActionListener listener) {
0924: enableThreadsMonitoringButton.removeActionListener(listener);
0925: }
0926:
0927: public void requestFocus() {
0928: SwingUtilities.invokeLater(new Runnable() { // must be invoked lazily to override default focus of first component
0929: public void run() {
0930: if (table != null) {
0931: table.requestFocus();
0932: }
0933: }
0934: });
0935: }
0936:
0937: public void threadsMonitoringDisabled() {
0938: threadsMonitoringEnabled = false;
0939: ((CardLayout) (contentPanel.getLayout())).show(contentPanel,
0940: ENABLE_THREADS_PROFILING);
0941: updateZoomButtonsEnabledState();
0942: threadsSelectionCombo.setEnabled(false);
0943: }
0944:
0945: public void threadsMonitoringEnabled() {
0946: threadsMonitoringEnabled = true;
0947: ((CardLayout) (contentPanel.getLayout())).show(contentPanel,
0948: THREADS_TABLE);
0949: updateZoomButtonsEnabledState();
0950: threadsSelectionCombo.setEnabled(true);
0951: }
0952:
0953: boolean supportsSleepingState() {
0954: return supportsSleepingState;
0955: }
0956:
0957: private JTable createViewTable() {
0958: return new JExtendedTable(new ThreadsTableModel()) {
0959: public void mouseMoved(MouseEvent event) {
0960: // Identify table row and column at cursor
0961: int row = rowAtPoint(event.getPoint());
0962: int column = columnAtPoint(event.getPoint());
0963:
0964: // Only celltip for thread name is supported
0965: if (getColumnClass(column) != ThreadNameCellRenderer.class) {
0966: CellTipManager.sharedInstance().setEnabled(false);
0967:
0968: return;
0969: }
0970:
0971: // Return if table cell is the same as in previous event
0972: if ((row == lastRow) && (column == lastColumn)) {
0973: return;
0974: }
0975:
0976: lastRow = row;
0977: lastColumn = column;
0978:
0979: if ((row < 0) || (column < 0)) {
0980: CellTipManager.sharedInstance().setEnabled(false);
0981:
0982: return;
0983: }
0984:
0985: Component cellRenderer = ((ThreadNameCellRenderer) (getCellRenderer(
0986: row, column)))
0987: .getTableCellRendererComponentPersistent(this ,
0988: getValueAt(row, column), false, false,
0989: row, column);
0990: Rectangle cellRect = getCellRect(row, column, false);
0991:
0992: // Return if celltip is not supported for the cell
0993: if (cellRenderer == null) {
0994: CellTipManager.sharedInstance().setEnabled(false);
0995:
0996: return;
0997: }
0998:
0999: int horizontalAlignment = ((ThreadNameCellRenderer) cellRenderer)
1000: .getHorizontalAlignment();
1001:
1002: if ((horizontalAlignment == SwingConstants.TRAILING)
1003: || (horizontalAlignment == SwingConstants.RIGHT)) {
1004: rendererRect = new Rectangle(
1005: (cellRect.x + cellRect.width)
1006: - cellRenderer.getPreferredSize().width,
1007: cellRect.y,
1008: cellRenderer.getPreferredSize().width,
1009: cellRenderer.getPreferredSize().height);
1010: } else {
1011: rendererRect = new Rectangle(cellRect.x,
1012: cellRect.y,
1013: cellRenderer.getPreferredSize().width,
1014: cellRenderer.getPreferredSize().height);
1015: }
1016:
1017: // Return if cell contents is fully visible
1018: if ((rendererRect.x >= cellRect.x)
1019: && ((rendererRect.x + rendererRect.width) <= (cellRect.x + cellRect.width))) {
1020: CellTipManager.sharedInstance().setEnabled(false);
1021:
1022: return;
1023: }
1024:
1025: while (cellTip.getComponentCount() > 0) {
1026: cellTip.remove(0);
1027: }
1028:
1029: cellTip.add(cellRenderer, BorderLayout.CENTER);
1030: cellTip.setPreferredSize(new Dimension(
1031: rendererRect.width + 2, getRowHeight(row) + 2));
1032:
1033: CellTipManager.sharedInstance().setEnabled(true);
1034: }
1035: };
1036: }
1037:
1038: private JPopupMenu initPopupMenu() {
1039: JPopupMenu popup = new JPopupMenu();
1040:
1041: showOnlySelectedThreads = new JMenuItem(SELECTED_THREADS_ITEM);
1042:
1043: if (detailsCallback != null) {
1044: Font boldfont = popup.getFont().deriveFont(Font.BOLD);
1045: showThreadsDetails = new JMenuItem(THREAD_DETAILS_ITEM);
1046: showThreadsDetails.setFont(boldfont);
1047: popup.add(showThreadsDetails);
1048: popup.add(new JSeparator());
1049: }
1050:
1051: popup.add(showOnlySelectedThreads);
1052:
1053: return popup;
1054: }
1055:
1056: private void performDefaultAction() {
1057: int[] array = table.getSelectedRows();
1058:
1059: for (int i = 0; i < array.length; i++) {
1060: array[i] = ((Integer) filteredDataToDataIndex.get(array[i]))
1061: .intValue();
1062: }
1063:
1064: ThreadsPanel.this .detailsCallback.showDetails(array);
1065: }
1066:
1067: // @AWTBound
1068: private void refreshUI() {
1069: if (!isShowing()) {
1070: return;
1071: }
1072:
1073: updateFilteredData();
1074: refreshViewData();
1075: updateScrollbar();
1076: updateZoomButtonsEnabledState();
1077: table.invalidate();
1078: ThreadsPanel.this .revalidate(); // needed to reflect table height increase when new threads appear
1079: ThreadsPanel.this .repaint(); // needed to paint the table even if no relayout happens
1080: }
1081:
1082: /** Updates internal view-related data based on changed conditions (new data, change in layout),
1083: * to maintain the view in expected condition after the change.
1084: */
1085: private void refreshViewData() {
1086: if (scaleToFit) {
1087: long dataLen = manager.getEndTime()
1088: - manager.getStartTime();
1089: int viewLen = table.getTableHeader().getHeaderRect(
1090: DISPLAY_COLUMN_INDEX).width;
1091: float currentResolution = (float) dataLen
1092: / Math.max(viewLen - RIGHT_DISPLAY_MARGIN
1093: - LEFT_DISPLAY_MARGIN, 1);
1094: viewStart = manager.getStartTime()
1095: - (long) (currentResolution * LEFT_DISPLAY_MARGIN);
1096: viewEnd = manager.getEndTime()
1097: + (long) (currentResolution * RIGHT_DISPLAY_MARGIN);
1098: } else {
1099: long rightMarginInTime = (long) (zoomResolutionPerPixel * RIGHT_DISPLAY_MARGIN);
1100: long leftMarginInTime = (long) (zoomResolutionPerPixel * LEFT_DISPLAY_MARGIN);
1101: long widthInTime = (long) (zoomResolutionPerPixel * table
1102: .getTableHeader().getHeaderRect(
1103: DISPLAY_COLUMN_INDEX).width);
1104:
1105: if (viewStart == -1) { // the first data came
1106: viewStart = manager.getStartTime() - leftMarginInTime;
1107: viewEnd = viewStart + widthInTime;
1108: }
1109:
1110: if (trackingEnd) {
1111: viewEnd = manager.getEndTime() + rightMarginInTime;
1112: viewStart = viewEnd - widthInTime;
1113:
1114: if (viewStart < (manager.getStartTime() - leftMarginInTime)) { // data do not fill display yet
1115: viewStart = manager.getStartTime()
1116: - leftMarginInTime;
1117: viewEnd = viewStart + widthInTime;
1118: }
1119: } else {
1120: if (viewStart < manager.getStartTime()) {
1121: viewStart = manager.getStartTime()
1122: - rightMarginInTime;
1123: }
1124:
1125: viewEnd = viewStart + widthInTime;
1126: }
1127: }
1128: }
1129:
1130: /** Creates new filteredDataToDataIndex according to the current filter criterion */
1131: private void updateFilteredData() {
1132: if (threadsSelectionCombo.getSelectedItem() == VIEW_THREADS_SELECTION) {
1133: return; // do nothing, data already filtered
1134: }
1135:
1136: filteredDataToDataIndex.clear();
1137:
1138: for (int i = 0; i < manager.getThreadsCount(); i++) {
1139: // view all threads
1140: if (threadsSelectionCombo.getSelectedItem().equals(
1141: VIEW_THREADS_ALL)) {
1142: filteredDataToDataIndex.add(new Integer(i));
1143:
1144: continue;
1145: }
1146:
1147: // view live threads
1148: if (threadsSelectionCombo.getSelectedItem().equals(
1149: VIEW_THREADS_LIVE)) {
1150: ThreadData threadData = manager.getThreadData(i);
1151:
1152: if (threadData.size() > 0) {
1153: byte state = threadData.getLastState();
1154:
1155: if (state != CommonConstants.THREAD_STATUS_ZOMBIE) {
1156: filteredDataToDataIndex.add(new Integer(i));
1157: }
1158: }
1159:
1160: continue;
1161: }
1162:
1163: // view finished threads
1164: if (threadsSelectionCombo.getSelectedItem().equals(
1165: VIEW_THREADS_FINISHED)) {
1166: ThreadData threadData = manager.getThreadData(i);
1167:
1168: if (threadData.size() > 0) {
1169: byte state = threadData.getLastState();
1170:
1171: if (state == CommonConstants.THREAD_STATUS_ZOMBIE) {
1172: filteredDataToDataIndex.add(new Integer(i));
1173: }
1174: } else {
1175: // No state defined -> THREAD_STATUS_ZOMBIE assumed (thread could finish when monitoring was disabled)
1176: filteredDataToDataIndex.add(new Integer(i));
1177: }
1178:
1179: continue;
1180: }
1181: }
1182: }
1183:
1184: private void updateScrollbar() {
1185: internalScrollbarChange = true;
1186:
1187: if (scrollBar.isVisible() == scaleToFit) {
1188: scrollBar.setVisible(!scaleToFit);
1189: }
1190:
1191: if (!scaleToFit) {
1192: int rightMarginInTime = (int) (zoomResolutionPerPixel * RIGHT_DISPLAY_MARGIN);
1193: int leftMarginInTime = (int) (zoomResolutionPerPixel * RIGHT_DISPLAY_MARGIN);
1194:
1195: int value = (int) (viewStart - manager.getStartTime())
1196: + leftMarginInTime;
1197: int extent = (int) (viewEnd - viewStart);
1198: int intMax = (int) (manager.getEndTime() - manager
1199: .getStartTime())
1200: + rightMarginInTime;
1201:
1202: // System.out.println("max: "+intMax);
1203: // System.out.println("value: "+value);
1204: // System.out.println("extent: "+extent);
1205: boolean shouldBeVisible = true;
1206:
1207: if ((value == 0) && ((intMax - (value + extent)) <= 0)) {
1208: shouldBeVisible = false;
1209: }
1210:
1211: if (scrollBar.isVisible() != shouldBeVisible) {
1212: scrollBar.setVisible(shouldBeVisible);
1213: }
1214:
1215: if (shouldBeVisible) {
1216: scrollBar.setValues(value, extent, -leftMarginInTime,
1217: intMax);
1218: scrollBar.setBlockIncrement((int) (extent * 0.95f));
1219: scrollBar.setUnitIncrement(Math.max(
1220: (int) (zoomResolutionPerPixel * 5), 1)); // at least 1
1221: }
1222: }
1223:
1224: internalScrollbarChange = false;
1225: }
1226:
1227: // ---------------------------------------------------------------------------------------
1228: // Sleeping state support
1229: private void updateSupportsSleepingState(
1230: boolean supportsSleepingState) {
1231: if (this .supportsSleepingState != supportsSleepingState) {
1232: this .supportsSleepingState = supportsSleepingState;
1233: sleepingLegend.setVisible(supportsSleepingState);
1234: }
1235: }
1236:
1237: /* public static void main(String[] args) {
1238: JFrame frame = new JFrame("Threads view test");
1239: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
1240: frame.getContentPane().setLayout(new BorderLayout());
1241: ThreadsDataManager threadsManager = new ThreadsDataManager();
1242: frame.getContentPane().add(new ThreadsPanel(threadsManager, null, true), BorderLayout.CENTER);
1243: frame.setSize(800, 600);
1244: frame.show();
1245: }
1246: */
1247:
1248: // ---------------------------------------------------------------------------------------
1249: // Private methods
1250: private void updateZoomButtonsEnabledState() {
1251: if (!threadsMonitoringEnabled) {
1252: zoomInButton.setEnabled(false);
1253: zoomOutButton.setEnabled(false);
1254: scaleToFitButton.setEnabled(false);
1255: } else {
1256: if (scaleToFit) {
1257: zoomInButton.setEnabled(false);
1258: zoomOutButton.setEnabled(false);
1259: } else {
1260: zoomInButton.setEnabled(zoomResolutionPerPixel > 0.1);
1261:
1262: // zoom out is enabled up until the actual data only cover 1/4 of the display area
1263: int viewWidth = table.getTableHeader().getHeaderRect(
1264: DISPLAY_COLUMN_INDEX).width;
1265: zoomOutButton
1266: .setEnabled((zoomResolutionPerPixel * viewWidth) < (2f * (manager
1267: .getEndTime() - manager.getStartTime())));
1268: }
1269:
1270: scaleToFitButton.setEnabled(true);
1271: scaleToFitButton
1272: .setToolTipText(scaleToFit ? FIXED_SCALE_TOOLTIP
1273: : SCALE_TO_FIT_TOOLTIP);
1274: }
1275: }
1276: }
|