/* * 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.core.explorer; import com.sun.tools.visualvm.core.datasource.DataSource; import com.sun.tools.visualvm.core.datasource.Storage; import com.sun.tools.visualvm.core.datasupport.Positionable; import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptor; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Set; import javax.swing.Icon; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; /** * * @author Jiri Sedlacek */ final class ExplorerNode extends DefaultMutableTreeNode implements Positionable { static final String PROPERTY_RELATIVE_POSITION = "prop_relative_position"; // NOI18N private String name; private Icon icon; private int preferredPosition; private int autoExpansionPolicy; private boolean defaultComparator = true; private ExplorerNodesComparator comparator = new ExplorerNodesComparator(new PositionableComparator()); private int maxEndPosition = -1; private int maxLastPosition = -1; private final Map<DataSource, Integer> endPositions = Collections.synchronizedMap(new HashMap()); private final Map<DataSource, Integer> lastPositions = Collections.synchronizedMap(new HashMap()); private boolean firstExpansionFlag = true; public ExplorerNode(DataSource dataSource) { super(dataSource); } public String getName() { return name; } public Icon getIcon() { return icon; } public DataSource getUserObject() { return (DataSource)super.getUserObject(); } public void addNode(ExplorerNode newChild) { addNodes(Collections.singleton(newChild)); } public void addNodes(Set<ExplorerNode> newChildren) { int originalChildCount = getChildCount(); for (ExplorerNode child : newChildren) { add(child); checkAddRelativePosition(child); } sortChildren(); boolean shouldExpand = false; boolean firstChildAdded = originalChildCount == 0 && getChildCount() > 0; switch (autoExpansionPolicy) { // case DataSourceDescriptor.EXPAND_NEVER: // break; case DataSourceDescriptor.EXPAND_ON_FIRST_CHILD: if (firstExpansionFlag && firstChildAdded) shouldExpand = true; firstExpansionFlag = false; break; case DataSourceDescriptor.EXPAND_ON_EACH_FIRST_CHILD: if (firstChildAdded) shouldExpand = true; break; case DataSourceDescriptor.EXPAND_ON_EACH_NEW_CHILD: case DataSourceDescriptor.EXPAND_ON_EACH_CHILD_CHANGE: if (newChildren.size() > 0) shouldExpand = true; break; } if (shouldExpand) ExplorerSupport.sharedInstance().expandNode(this); } public void remove(MutableTreeNode aChild) { super.remove(aChild); checkRemoveRelativePosition((ExplorerNode)aChild); if (autoExpansionPolicy == DataSourceDescriptor.EXPAND_ON_EACH_CHILD_CHANGE) ExplorerSupport.sharedInstance().expandNode(this); } public String toString() { return getName(); } public int getPreferredPosition() { return preferredPosition; } boolean setName(String name) { // No parent, no structure changes if (parent == null) { this.name = name; return false; // Name changed } else if (this.name == null || !this.name.equals(name)) { this.name = name; ((ExplorerNode)parent).sortChildren(); return true; // Name unchanged } else { return false; } } void setIcon(Icon icon) { this.icon = icon; } void setPreferredPosition(int preferredPosition) { this.preferredPosition = preferredPosition; } boolean setComparator(Comparator<DataSource> comparator) { boolean change = false; if (comparator == null) { change = !defaultComparator; if (change) this.comparator = new ExplorerNodesComparator(new PositionableComparator()); defaultComparator = true; } else { change = defaultComparator || !this.comparator.uses(comparator); if (change) this.comparator = new ExplorerNodesComparator(comparator); defaultComparator = false; } if (change) sortChildren(); return change; } void setAutoExpansionPolicy(int autoExpansionPolicy) { this.autoExpansionPolicy = autoExpansionPolicy; firstExpansionFlag = true; } private void sortChildren() { if (getChildCount() == 0) return; Collections.sort(children, comparator); } private void checkAddRelativePosition(ExplorerNode node) { int pos = node.getPreferredPosition(); DataSource d = node.getUserObject(); if (pos == Positionable.POSITION_AT_THE_END) addPosition(d, endPositions); else if (pos == Positionable.POSITION_LAST) addPosition(d, lastPositions); } private void addPosition(DataSource node, Map<DataSource, Integer> positions) { Storage s = node.getStorage(); String PREF = DataSourceDescriptor.PROPERTY_PREFERRED_POSITION; int nodePos = 0; boolean posDirty = true; try { // throws NullPointerException nodePos = getMaxPosition(positions) + 1; // throws NumberFormatException nodePos = Integer.parseInt(s.getCustomProperty(PROPERTY_RELATIVE_POSITION)); posDirty = false; } catch (Exception e) {} if (s.getCustomProperty(PREF) != null && posDirty) s.setCustomProperty(PROPERTY_RELATIVE_POSITION, Integer.toString(nodePos)); positions.put(node, nodePos); updateMaxPosition(positions, nodePos, false); } private void checkRemoveRelativePosition(ExplorerNode node) { int pos = node.getPreferredPosition(); DataSource d = node.getUserObject(); if (pos == Positionable.POSITION_AT_THE_END) removePosition(d, endPositions); else if (pos == Positionable.POSITION_LAST) removePosition(d, lastPositions); } private void removePosition(DataSource node, Map<DataSource, Integer> positions) { int nodePos = positions.remove(node); updateMaxPosition(positions, nodePos, true); } private int getMaxPosition(Map<DataSource, Integer> positions) { if (positions == endPositions) return maxEndPosition; else return maxLastPosition; } private void setMaxPosition(Map<DataSource, Integer> positions, int newMax) { if (positions == endPositions) maxEndPosition = newMax; else maxLastPosition = newMax; } private void updateMaxPosition(Map<DataSource, Integer> positions, int position, boolean remove) { int maxPos = getMaxPosition(positions); if (!remove && maxPos < position) setMaxPosition(positions, position); else if (remove && maxPos == position) { int newMax = -1; Collection<Integer> values = positions.values(); for (int i : values) if (i > newMax) newMax = i; setMaxPosition(positions, newMax); } } private class PositionableComparator extends DataSourcesComparator { protected int getRelativePosition(DataSource d, int positionType) { if (positionType == Positionable.POSITION_AT_THE_END) return endPositions.get(d); else if (positionType == Positionable.POSITION_LAST) return lastPositions.get(d); else return positionType; } } }