/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.visualvm.sampler.memory;
import com.sun.tools.visualvm.application.jvm.HeapHistogram;
import com.sun.tools.visualvm.application.jvm.HeapHistogram.ClassInfo;
import com.sun.tools.visualvm.sampler.AbstractSamplerSupport;
import com.sun.tools.visualvm.uisupport.HTMLTextArea;
import com.sun.tools.visualvm.uisupport.SeparatorLine;
import com.sun.tools.visualvm.uisupport.TransparentToolBar;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.lang.management.MemoryMXBean;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import org.netbeans.lib.profiler.global.CommonConstants;
import org.netbeans.lib.profiler.ui.UIConstants;
import org.netbeans.lib.profiler.ui.UIUtils;
import org.netbeans.lib.profiler.ui.components.FilterComponent;
import org.netbeans.lib.profiler.ui.components.JExtendedTable;
import org.netbeans.lib.profiler.ui.components.table.ClassNameTableCellRenderer;
import org.netbeans.lib.profiler.ui.components.table.CustomBarCellRenderer;
import org.netbeans.lib.profiler.ui.components.table.DiffBarCellRenderer;
import org.netbeans.lib.profiler.ui.components.table.ExtendedTableModel;
import org.netbeans.lib.profiler.ui.components.table.JExtendedTablePanel;
import org.netbeans.lib.profiler.ui.components.table.LabelBracketTableCellRenderer;
import org.netbeans.lib.profiler.ui.components.table.LabelTableCellRenderer;
import org.netbeans.lib.profiler.ui.components.table.SortableTableModel;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
/**
*
* @author Jiri Sedlacek
* @author Tomas Hurka
*/
final class MemoryView extends JPanel {
static final int MODE_HEAP = 1;
static final int MODE_PERMGEN = 2;
static final int MODE_THREADALLOC = 3;
private final int mode;
private final AbstractSamplerSupport.Refresher refresher;
private boolean forceRefresh = false;
private final MemoryMXBean memoryBean;
private final MemorySamplerSupport.HeapDumper heapDumper;
private final MemorySamplerSupport.SnapshotDumper snapshotDumper;
MemoryView(AbstractSamplerSupport.Refresher refresher, int mode,
MemoryMXBean memoryBean, MemorySamplerSupport.SnapshotDumper snapshotDumper,
MemorySamplerSupport.HeapDumper heapDumper) {
this.refresher = refresher;
this.mode = mode;
this.memoryBean = memoryBean;
this.snapshotDumper = snapshotDumper;
this.heapDumper = heapDumper;
initColumnsData();
initComponents();
addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
if (isShowing()) MemoryView.this.refresher.refresh();
}
}
});
}
void initSession() {
if (snapshotButton != null) snapshotButton.setEnabled(false);
}
boolean isPaused() {
return pauseButton.isSelected() && !forceRefresh;
}
boolean isEmpty() {
return resTableModel.getRowCount() == 0;
}
void refresh(HeapHistogram histogram) {
if (histogram == null || isPaused()) return;
forceRefresh = false;
if (deltaButton.isSelected()) {
if (baseClasses == null) {
baseClasses = new ArrayList(classes);
baseTotalBytes = totalBytes;
baseTotalInstances = totalInstances;
columnRenderers[1] = diffBarCellRenderer;
columnRenderers[2] = labelTableCellRenderer;
columnRenderers[3] = labelTableCellRenderer;
updateColumnRenderers();
}
Collection<ClassInfo> newClasses = getHistogram(histogram);
classes = computeDeltaClasses(baseClasses, newClasses);
totalClasses = baseClasses.size() - newClasses.size();
totalBytes = getTotalBytes(histogram) - baseTotalBytes;
totalInstances = getTotalInstances(histogram) - baseTotalInstances;
long maxAbsDiffBytes = 0;
for (ClassInfo cInfo : classes)
maxAbsDiffBytes = Math.max(maxAbsDiffBytes, Math.abs(cInfo.getBytes()));
diffBarCellRenderer.setMaximum(maxAbsDiffBytes);
diffBarCellRenderer.setMinimum(-maxAbsDiffBytes);
} else {
if (baseClasses != null) {
baseClasses = null;
baseTotalBytes = -1;
baseTotalInstances = -1;
columnRenderers[1] = customBarCellRenderer;
columnRenderers[2] = labelBracketTableCellRenderer;
columnRenderers[3] = labelBracketTableCellRenderer;
updateColumnRenderers();
}
classes.clear();
classes.addAll(getHistogram(histogram));
totalClasses = classes.size();
totalBytes = getTotalBytes(histogram);
totalInstances = getTotalInstances(histogram);
customBarCellRenderer.setMaximum(totalBytes);
}
updateData(false);
refreshUI();
if (snapshotButton != null) snapshotButton.setEnabled(true);
}
void terminate() {
// refreshRateLabel.setEnabled(false);
// refreshCombo.setEnabled(false);
// refreshUnitsLabel.setEnabled(false);
pauseButton.setEnabled(false);
refreshButton.setEnabled(false);
deltaButton.setEnabled(false);
gcButton.setEnabled(false);
heapdumpButton.setEnabled(false);
}
private Collection getHistogram(HeapHistogram histogram) {
if (mode == MODE_HEAP) return histogram.getHeapHistogram();
if (mode == MODE_PERMGEN) return histogram.getPermGenHistogram();
return null;
}
private long getTotalBytes(HeapHistogram histogram) {
if (mode == MODE_HEAP) return histogram.getTotalHeapBytes();
if (mode == MODE_PERMGEN) return histogram.getTotalPermGenHeapBytes();
return -1;
}
private long getTotalInstances(HeapHistogram histogram) {
if (mode == MODE_HEAP) return histogram.getTotalHeapInstances();
if (mode == MODE_PERMGEN) return histogram.getTotalPerGenInstances();
return -1;
}
private static List<ClassInfo> computeDeltaClasses(Collection<ClassInfo> basis, Collection<ClassInfo> changed) {
Map<String, DeltaClassInfo> deltaMap = new HashMap((int)(basis.size() * 1.3));
for (ClassInfo cInfo : basis)
deltaMap.put(cInfo.getName(), new DeltaClassInfo(cInfo, true));
for (ClassInfo cInfo : changed) {
DeltaClassInfo bInfo = deltaMap.get(cInfo.getName());
if (bInfo != null) bInfo.add(cInfo);
else deltaMap.put(cInfo.getName(), new DeltaClassInfo(cInfo, false));
}
return new ArrayList(deltaMap.values());
}
private void updateData(boolean sortOnly) {
int selectedRow = resTable.getSelectedRow();
String selectedRowContents = null;
if (selectedRow != -1)
selectedRowContents = (String) resTable.getValueAt(selectedRow, 0);
if (!sortOnly) filterData();
sortData();
resTableModel.fireTableDataChanged();
if (selectedRowContents != null)
resTable.selectRowByContents(selectedRowContents, 0, false);
}
private void filterData() {
filteredSortedIndexes.clear();
String[] filterStrings = FilterComponent.getFilterValues(filterString);
if (filterType == CommonConstants.FILTER_NONE ||
filterStrings == null || filterStrings[0].equals("")) { // NOI18N
for (int i = 0; i < classes.size(); i++) filteredSortedIndexes.add(i);
} else {
for (int i = 0; i < classes.size(); i++)
if (passedFilters(classes.get(i).getName(), filterStrings, filterType))
filteredSortedIndexes.add(i);
}
}
private static boolean passedFilters(String value, String[] filters, int type) {
for (int i = 0; i < filters.length; i++)
if (passedFilter(value, filters[i], type)) return true;
return false;
}
private static boolean passedFilter(String value, String filter, int type) {
// Case sensitive comparison:
/*switch (type) {
case CommonConstants.FILTER_STARTS_WITH:
return value.startsWith(filter);
case CommonConstants.FILTER_CONTAINS:
return value.indexOf(filter) != -1;
case CommonConstants.FILTER_ENDS_WITH:
return value.endsWith(filter);
case CommonConstants.FILTER_EQUALS:
return value.equals(filter);
case CommonConstants.FILTER_REGEXP:
return value.matches(filter);
}*/
// Case insensitive comparison (except regexp):
switch (type) {
case CommonConstants.FILTER_STARTS_WITH:
return value.regionMatches(true, 0, filter, 0, filter.length()); // case insensitive startsWith, optimized
case CommonConstants.FILTER_CONTAINS:
return value.toLowerCase().indexOf(filter.toLowerCase()) != -1; // case insensitive indexOf, NOT OPTIMIZED
case CommonConstants.FILTER_ENDS_WITH:
// case insensitive endsWith, optimized
return value.regionMatches(true, value.length() - filter.length(), filter, 0, filter.length());
case CommonConstants.FILTER_EQUALS:
return value.equalsIgnoreCase(filter); // case insensitive equals
case CommonConstants.FILTER_REGEXP:
return value.matches(filter); // still case sensitive!
}
return false;
}
private void sortData() {
Collections.sort(filteredSortedIndexes, new Comparator() {
public int compare(Object o1, Object o2) {
Integer index1 = (Integer)o1;
Integer index2 = (Integer)o2;
ClassInfo class1 = classes.get(index1);
ClassInfo class2 = classes.get(index2);
switch (sortingColumn) {
case 0:
return sortOrder ? class1.getName().compareTo(class2.getName()) :
class2.getName().compareTo(class1.getName());
case 1:
case 2:
return sortOrder ? ((Long)class1.getBytes()).compareTo(class2.getBytes()) :
((Long)class2.getBytes()).compareTo(class1.getBytes());
case 3:
return sortOrder ? ((Long)class1.getInstancesCount()).compareTo(class2.getInstancesCount()) :
((Long)class2.getInstancesCount()).compareTo(class1.getInstancesCount());
default:
return 0;
}
}
});
}
private JExtendedTable initTable() {
resTableModel = new ExtendedTableModel(new SortableTableModel() {
public String getColumnName(int col) {
return columnNames[col];
}
public int getRowCount() {
return filteredSortedIndexes.size();
}
public int getColumnCount() {
return columnNames.length;
}
public Class getColumnClass(int col) {
return columnTypes[col];
}
public Object getValueAt(int row, int col) {
ClassInfo classs = classes.get(filteredSortedIndexes.get(row));
boolean deltas = baseClasses != null;
long bytes = classs.getBytes();
long instances = classs.getInstancesCount();
NumberFormat formatter = NumberFormat.getInstance();
switch (col) {
case 0:
return classs.getName();
case 1:
return bytes;
case 2:
if (deltas) {
return bytes > 0 ? "+" + formatter.format(bytes) : formatter.format(bytes); // NOI18N
} else {
return bytes == 0 ? "0 (0.0%)" : formatter.format(bytes) + " (" + getPercentValue(bytes, totalBytes) + "%)"; // NOI18N
}
case 3:
if (deltas) {
return instances > 0 ? "+" + formatter.format(instances) : formatter.format(instances); // NOI18N
} else {
return instances == 0 ? "0 (0.0%)" : formatter.format(instances) + " (" + getPercentValue(instances, totalInstances) + "%)"; // NOI18N
}
default:
return null;
}
}
private String getPercentValue(float value, float basevalue) {
int basis = (int) (value / basevalue * 1000f);
int percent = basis / 10;
int permille = basis % 10;
return "" + percent + "." + permille; // NOI18N
}
public String getColumnToolTipText(int col) {
return columnToolTips[col];
}
public void sortByColumn(int column, boolean order) {
sortingColumn = column;
sortOrder = order;
updateData(true);
}
/**
* @param column The table column index
* @return Initial sorting for the specified column - if true, ascending, if false descending
*/
public boolean getInitialSorting(int column) {
switch (column) {
case 0:
return true;
default:
return false;
}
}
});
resTable = new JExtendedTable(resTableModel) {
public void doLayout() {
int columnsWidthsSum = 0;
int realFirstColumn = -1;
int index;
for (int i = 0; i < resTableModel.getColumnCount(); i++) {
index = resTableModel.getRealColumn(i);
if (index == 0) {
realFirstColumn = i;
} else {
columnsWidthsSum += getColumnModel().getColumn(i).getPreferredWidth();
}
}
if (realFirstColumn != -1) {
getColumnModel().getColumn(realFirstColumn)
.setPreferredWidth(Math.max(getWidth() - columnsWidthsSum, minNamesColumnWidth));
}
super.doLayout();
}
;
};
resTableModel.setTable(resTable);
resTableModel.setInitialSorting(sortingColumn, sortOrder);
resTable.setRowSelectionAllowed(true);
resTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
resTable.setGridColor(UIConstants.TABLE_VERTICAL_GRID_COLOR);
resTable.setSelectionBackground(UIConstants.TABLE_SELECTION_BACKGROUND_COLOR);
resTable.setSelectionForeground(UIConstants.TABLE_SELECTION_FOREGROUND_COLOR);
resTable.setShowHorizontalLines(UIConstants.SHOW_TABLE_HORIZONTAL_GRID);
resTable.setShowVerticalLines(UIConstants.SHOW_TABLE_VERTICAL_GRID);
resTable.setRowMargin(UIConstants.TABLE_ROW_MARGIN);
resTable.setRowHeight(UIUtils.getDefaultRowHeight() + 2);
resTable.getAccessibleContext().setAccessibleName(""); // NOI18N
resTable.getAccessibleContext().setAccessibleDescription(""); // NOI18N
// resTable.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
// .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "DEFAULT_ACTION"); // NOI18N
// resTable.getActionMap().put("DEFAULT_ACTION", new AbstractAction() { // NOI18N
// public void actionPerformed(ActionEvent e) {
// performDefaultAction();
// }
// });
// Disable traversing table cells using TAB and Shift+TAB
Set keys = new HashSet(resTable.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
resTable.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
keys = new HashSet(resTable.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
keys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK));
resTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, keys);
setColumnsData();
return resTable;
}
protected void initColumnsData() {
int maxWidth = getFontMetrics(getFont()).charWidth('W') * 13; // NOI18N // initial width of data columns
minNamesColumnWidth = getFontMetrics(getFont()).charWidth('W') * 30; // NOI18N
ClassNameTableCellRenderer classNameTableCellRenderer = new ClassNameTableCellRenderer();
customBarCellRenderer = new CustomBarCellRenderer(0, 100);
diffBarCellRenderer = new DiffBarCellRenderer(0, 100);
labelTableCellRenderer = new LabelTableCellRenderer(JLabel.TRAILING);
labelBracketTableCellRenderer = new LabelBracketTableCellRenderer(JLabel.TRAILING);
columnNames = new String[] {
NbBundle.getMessage(MemoryView.class, "COL_Class_name"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Bytes_rel"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Bytes"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Instances") }; // NOI18N
columnToolTips = new String[] {
NbBundle.getMessage(MemoryView.class, "COL_Class_name"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Bytes_rel"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Bytes"), // NOI18N
NbBundle.getMessage(MemoryView.class, "COL_Instances") }; // NOI18N
columnTypes = new Class[] { String.class, Number.class, String.class, String.class };
columnRenderers = new TableCellRenderer[] {
classNameTableCellRenderer, customBarCellRenderer,
labelBracketTableCellRenderer, labelBracketTableCellRenderer };
columnWidths = new int[] { maxWidth, maxWidth, maxWidth, maxWidth };
}
private void setColumnsData() {
TableColumnModel colModel = resTable.getColumnModel();
colModel.getColumn(0).setPreferredWidth(minNamesColumnWidth);
int index;
for (int i = 0; i < colModel.getColumnCount(); i++) {
index = resTableModel.getRealColumn(i);
if (index == 0) {
colModel.getColumn(i).setPreferredWidth(minNamesColumnWidth);
} else {
colModel.getColumn(i).setPreferredWidth(columnWidths[index - 1]);
}
colModel.getColumn(i).setCellRenderer(columnRenderers[index]);
}
}
private void updateColumnRenderers() {
TableColumnModel colModel = resTable.getColumnModel();
for (int i = 0; i < colModel.getColumnCount(); i++)
colModel.getColumn(i).setCellRenderer(
columnRenderers[resTableModel.getRealColumn(i)]);
}
// private void performDefaultAction() {
// int[] array = resTable.getSelectedRows();
//
// for (int i = 0; i < array.length; i++)
// array[i] = filteredDataToDataIndex.get(array[i]).threadIndex;
//
// ThreadsTablePanel.this.detailsCallback.showDetails(array);
// }
private void initComponents() {
setLayout(new BorderLayout());
setOpaque(false);
final TransparentToolBar toolBar = new TransparentToolBar();
// refreshRateLabel = new JLabel("Refresh: ");
// refreshRateLabel.setToolTipText("Live results refresh rate [ms]");
// toolBar.add(refreshRateLabel);
//
// Integer[] refreshRates = new Integer[] { 100, 200, 500, 1000, 2000, 5000, 10000 };
// refreshCombo = new JComboBox(refreshRates) {
// public Dimension getMinimumSize() { return getPreferredSize(); }
// public Dimension getMaximumSize() { return getPreferredSize(); }
// };
// refreshCombo.setToolTipText("Live results refresh rate [ms]");
// refreshCombo.setEditable(false);
// refreshCombo.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// refresher.setRefreshRate((Integer)refreshCombo.getSelectedItem());
// }
// });
// refreshCombo.setSelectedItem(refresher.getRefreshRate());
// refreshCombo.setRenderer(new ComboRenderer(refreshCombo));
// toolBar.add(refreshCombo);
//
// refreshUnitsLabel = new JLabel(" ms. ");
// refreshUnitsLabel.setToolTipText("Live results refresh rate [ms]");
// toolBar.add(refreshUnitsLabel);
pauseButton = new JToggleButton() {
protected void fireActionPerformed(ActionEvent event) {
boolean selected = pauseButton.isSelected();
refreshButton.setEnabled(selected);
if (!selected) refresher.refresh();
}
};
pauseButton.setIcon(new ImageIcon(ImageUtilities.loadImage(
"com/sun/tools/visualvm/sampler/resources/pause.png", true))); // NOI18N
pauseButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_Pause_results")); // NOI18N
pauseButton.setOpaque(false);
toolBar.addItem(pauseButton);
refreshButton = new JButton() {
protected void fireActionPerformed(ActionEvent event) {
forceRefresh = true;
refresher.refresh();
}
};
refreshButton.setIcon(new ImageIcon(ImageUtilities.loadImage(
"com/sun/tools/visualvm/sampler/resources/update.png", true))); // NOI18N
refreshButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_Update_results")); // NOI18N
refreshButton.setEnabled(pauseButton.isSelected());
refreshButton.setOpaque(false);
toolBar.addItem(refreshButton);
toolBar.addSeparator();
deltaButton = new JToggleButton(NbBundle.getMessage(MemoryView.class, "LBL_Deltas")) { // NOI18N
protected void fireActionPerformed(ActionEvent event) {
refresher.refresh();
}
};
deltaButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_Deltas")); // NOI18N
deltaButton.setOpaque(false);
toolBar.addItem(deltaButton);
if (snapshotDumper != null) {
toolBar.addSeparator();
snapshotButton = new JButton(NbBundle.getMessage(MemoryView.class,
"LBL_Snapshot"), new ImageIcon(ImageUtilities.loadImage( // NOI18N
"com/sun/tools/visualvm/sampler/resources/snapshot.png", true))) { // NOI18N
protected void fireActionPerformed(ActionEvent event) {
snapshotDumper.takeSnapshot((event.getModifiers() & Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) == 0);
}
};
snapshotButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_Snapshot")); // NOI18N
snapshotButton.setOpaque(false);
snapshotButton.setEnabled(false);
toolBar.addItem(snapshotButton);
}
toolBar.addFiller();
gcButton = new JButton(NbBundle.getMessage(MemoryView.class, "LBL_Gc")) { // NOI18N
protected void fireActionPerformed(ActionEvent event) {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
try { memoryBean.gc(); } catch (Exception e) {
setEnabled(false);
Exceptions.printStackTrace(e);
}
};
});
}
};
gcButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_Gc")); // NOI18N
gcButton.setOpaque(false);
gcButton.setEnabled(memoryBean != null);
toolBar.addItem(gcButton);
heapdumpButton = new JButton(NbBundle.getMessage(MemoryView.class, "LBL_HeapDump")) { // NOI18N
protected void fireActionPerformed(ActionEvent event) {
heapDumper.takeHeapDump((event.getModifiers() &
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) == 0);
}
};
heapdumpButton.setToolTipText(NbBundle.getMessage(MemoryView.class, "TOOLTIP_HeapDump")); // NOI18N
heapdumpButton.setOpaque(false);
heapdumpButton.setEnabled(heapDumper != null);
toolBar.addItem(heapdumpButton);
int maxHeight = pauseButton.getPreferredSize().height;
maxHeight = Math.max(maxHeight, refreshButton.getPreferredSize().height);
if (snapshotButton != null) maxHeight = Math.max(maxHeight, snapshotButton.getPreferredSize().height);
maxHeight = Math.max(maxHeight, deltaButton.getPreferredSize().height);
maxHeight = Math.max(maxHeight, gcButton.getPreferredSize().height);
maxHeight = Math.max(maxHeight, heapdumpButton.getPreferredSize().height);
int width = pauseButton.getPreferredSize().width;
Dimension size = new Dimension(maxHeight, maxHeight);
pauseButton.setMinimumSize(size);
pauseButton.setPreferredSize(size);
pauseButton.setMaximumSize(size);
width = refreshButton.getPreferredSize().width;
size = new Dimension(maxHeight, maxHeight);
refreshButton.setMinimumSize(size);
refreshButton.setPreferredSize(size);
refreshButton.setMaximumSize(size);
if (snapshotButton != null) {
width = snapshotButton.getPreferredSize().width;
size = new Dimension(width + 5, maxHeight);
snapshotButton.setMinimumSize(size);
snapshotButton.setPreferredSize(size);
snapshotButton.setMaximumSize(size);
}
width = deltaButton.getPreferredSize().width;
size = new Dimension(width + 5, maxHeight);
deltaButton.setMinimumSize(size);
deltaButton.setPreferredSize(size);
deltaButton.setMaximumSize(size);
width = gcButton.getPreferredSize().width;
size = new Dimension(width + 5, maxHeight);
gcButton.setMinimumSize(size);
gcButton.setPreferredSize(size);
gcButton.setMaximumSize(size);
width = heapdumpButton.getPreferredSize().width;
size = new Dimension(width + 5, maxHeight);
heapdumpButton.setMinimumSize(size);
heapdumpButton.setPreferredSize(size);
heapdumpButton.setMaximumSize(size);
// controlPanel.add(toolBar, BorderLayout.NORTH);
// controlPanel.add(new SeparatorLine(true), BorderLayout.CENTER);
JPanel resultsPanel = new JPanel(new BorderLayout());
resultsPanel.setOpaque(false);
JPanel areaPanel = new JPanel(new BorderLayout());
areaPanel.setOpaque(false);
area = new HTMLTextArea();
area.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
refreshUI();
areaPanel.add(area, BorderLayout.NORTH);
areaPanel.add(new SeparatorLine(true), BorderLayout.SOUTH);
resultsPanel.add(areaPanel, BorderLayout.NORTH);
add(TransparentToolBar.withSeparator(toolBar), BorderLayout.NORTH);
resTable = initTable();
resTable.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
MemoryView.this.revalidate();
}
});
resTablePanel = new JExtendedTablePanel(resTable);
resTablePanel.clearBorders();
resultsPanel.add(resTablePanel, BorderLayout.CENTER);
add(resultsPanel, BorderLayout.CENTER);
initFilterPanel();
// resTable.addKeyListener(new KeyAdapter() {
// public void keyPressed(KeyEvent e) {
// if ((e.getKeyCode() == KeyEvent.VK_CONTEXT_MENU)
// || ((e.getKeyCode() == KeyEvent.VK_F10) && (e.getModifiers() == InputEvent.SHIFT_MASK))) {
// int selectedRow = resTable.getSelectedRow();
//
// if (selectedRow != -1) {
// Rectangle cellRect = resTable.getCellRect(selectedRow, 0, false);
// popupMenu.show(e.getComponent(), ((cellRect.x + resTable.getSize().width) > 50) ? 50 : 5, cellRect.y);
// }
// }
// }
// });
//
// resTable.addMouseListener(new MouseAdapter() {
// public void mousePressed(MouseEvent e) {
// if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
// int line = resTable.rowAtPoint(e.getPoint());
//
// if ((line != -1) && (!resTable.isRowSelected(line))) {
// if (e.isControlDown()) {
// resTable.addRowSelectionInterval(line, line);
// } else {
// resTable.setRowSelectionInterval(line, line);
// }
// }
// }
// }
//
// public void mouseClicked(MouseEvent e) {
// int clickedLine = resTable.rowAtPoint(e.getPoint());
//
// if (clickedLine != -1) {
// if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
// popupMenu.show(e.getComponent(), e.getX(), e.getY());
// } else if ((e.getModifiers() == InputEvent.BUTTON1_MASK) && (e.getClickCount() == 2)) {
// performDefaultAction();
// }
// }
// }
//
// });
}
private void initFilterPanel() {
filterComponent = FilterComponent.create(true, true);
filterComponent.setFilter(filterString, filterType);
filterComponent.setHint(NbBundle.getMessage(MemoryView.class, "LBL_Class_filter")); // NOI18N
filterComponent.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
filterString = filterComponent.getFilterValue();
filterType = filterComponent.getFilterType();
updateData(false);
}
});
add(filterComponent.getComponent(), BorderLayout.SOUTH);
}
private void refreshUI() {
int selStart = area.getSelectionStart();
int selEnd = area.getSelectionEnd();
area.setText(getBasicTelemetry());
area.select(selStart, selEnd);
}
private String getBasicTelemetry() {
boolean deltas = baseClasses != null;
String sClasses = totalClasses == -1 ? "" : (deltas && totalClasses > 0 ? "+" : "") + NumberFormat.getInstance().format(totalClasses); // NOI18N
String sInstances = totalInstances == -1 ? "" : (deltas && totalInstances > 0 ? "+" : "") + NumberFormat.getInstance().format(totalInstances); // NOI18N
String sBytes = totalBytes == -1 ? "" : (deltas && totalBytes > 0 ? "+" : "") + NumberFormat.getInstance().format(totalBytes); // NOI18N
String ssClasses = NbBundle.getMessage(MemoryView.class, "LBL_Classes", sClasses); // NOI18N
String ssInstances = NbBundle.getMessage(MemoryView.class, "LBL_Instances", sInstances); // NOI18N
String ssBytes = NbBundle.getMessage(MemoryView.class, "LBL_Bytes", sBytes); // NOI18N
return "<nobr>" + ssClasses + " " + // NOI18N
ssInstances + " " + ssBytes + "</nobr>"; // NOI18N
}
private HTMLTextArea area;
// private JLabel refreshRateLabel;
// private JLabel refreshUnitsLabel;
// private JComboBox refreshCombo;
private AbstractButton snapshotButton;
private AbstractButton deltaButton;
private AbstractButton pauseButton;
private AbstractButton refreshButton;
private AbstractButton gcButton;
private AbstractButton heapdumpButton;
private JExtendedTable resTable;
private ExtendedTableModel resTableModel;
private JExtendedTablePanel resTablePanel;
private FilterComponent filterComponent;
private CustomBarCellRenderer customBarCellRenderer;
private DiffBarCellRenderer diffBarCellRenderer;
private LabelTableCellRenderer labelTableCellRenderer;
private LabelBracketTableCellRenderer labelBracketTableCellRenderer;
private String filterString = ""; // NOI18N
private int filterType = CommonConstants.FILTER_CONTAINS;
private List<ClassInfo> classes = new ArrayList();
private List<ClassInfo> baseClasses = new ArrayList(); // Needed to correctly setup table renderers
private List<Integer> filteredSortedIndexes = new ArrayList();
private int totalClasses = -1;
private long totalBytes, baseTotalBytes = -1;
private long totalInstances, baseTotalInstances = -1;
private int sortingColumn = 1;
private boolean sortOrder = false; // Defines the sorting order (ascending or descending)
private String[] columnNames;
private TableCellRenderer[] columnRenderers;
private String[] columnToolTips;
private Class[] columnTypes;
private int[] columnWidths;
private int minNamesColumnWidth; // minimal width of classnames columns
// private static class ComboRenderer implements ListCellRenderer {
//
// private ListCellRenderer renderer;
//
// ComboRenderer(JComboBox combo) {
// renderer = combo.getRenderer();
// if (renderer instanceof JLabel)
// ((JLabel)renderer).setHorizontalAlignment(JLabel.TRAILING);
// }
//
// public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
// return renderer.getListCellRendererComponent(list, NumberFormat.getInstance().format(value), index, isSelected, cellHasFocus);
// }
//
// }
private static class DeltaClassInfo extends ClassInfo {
String name;
long instancesCount;
long bytes;
DeltaClassInfo(ClassInfo cInfo, boolean negative) {
name = cInfo.getName();
instancesCount = negative ? -cInfo.getInstancesCount() : cInfo.getInstancesCount();
bytes = negative ? -cInfo.getBytes() : cInfo.getBytes();
}
void add(ClassInfo cInfo) {
instancesCount += cInfo.getInstancesCount();
bytes += cInfo.getBytes();
}
public String getName() { return name; }
public long getInstancesCount() { return instancesCount; }
public long getBytes() { return bytes; }
}
}