/* * 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 java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.JTree; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; import org.openide.windows.WindowManager; /** * Class for accessing the explorer tree. * * @author Jiri Sedlacek */ public final class ExplorerSupport { private static ExplorerSupport sharedInstance; private JTree mainTree; private Set<ExplorerSelectionListener> selectionListeners = Collections.synchronizedSet(new HashSet()); private Set<ExplorerExpansionListener> expansionListeners = Collections.synchronizedSet(new HashSet()); /** * Returns singleton instance of ExplorerSupport. * * @return singleton instance of ExplorerSupport. */ public static synchronized ExplorerSupport sharedInstance() { if (sharedInstance == null) sharedInstance = new ExplorerSupport(); return sharedInstance; } /** * Returns current DataSource position within its owner DataSource in explorer tree or -1 if the position cannot be determined. * * @param dataSource DataSource for which to get the position. * @return current DataSource position within its owner DataSource in explorer tree or -1 if the position cannot be determined. */ public int getDataSourcePosition(DataSource dataSource) { ExplorerNode node = getNode(dataSource); if (node == null) return -1; ExplorerNode parentNode = (ExplorerNode)node.getParent(); if (parentNode == null) return -1; return parentNode.getIndex(node); } /** * Selects DataSource in explorer tree. * * @param dataSource DataSource to be selected. */ public void selectDataSource(final DataSource dataSource) { if (dataSource == null) return; selectDataSources(Collections.singleton(dataSource)); } /** * Selects multiple DataSources in explorer tree. * * @param dataSources DataSources to be selected. */ public void selectDataSources(final Set<DataSource> dataSources) { if (dataSources.isEmpty()) return; WindowManager.getDefault().invokeWhenUIReady(new Runnable() { public void run() { List<TreePath> selectedPaths = new ArrayList(); for (DataSource dataSource : dataSources) { ExplorerNode node = getNode(dataSource); if (node != null) selectedPaths.add(getPath(node)); } mainTree.setSelectionPaths(selectedPaths.isEmpty() ? null : selectedPaths.toArray(new TreePath[selectedPaths.size()])); } }); } /** * Clears selection of explorer tree. */ public void clearSelection() { WindowManager.getDefault().invokeWhenUIReady(new Runnable() { public void run() { mainTree.clearSelection(); } }); } /** * Returns selected DataSources in explorer tree. * * @return selected DataSources in explorer tree. */ public Set<DataSource> getSelectedDataSources() { if (mainTree == null) return Collections.EMPTY_SET; TreePath[] selectedPaths = mainTree.getSelectionPaths(); if (selectedPaths == null) return Collections.EMPTY_SET; Set<DataSource> selectedDataSources = new HashSet(); for (TreePath treePath : selectedPaths) { DataSource dataSource = getDataSource(treePath); if (dataSource != null) selectedDataSources.add(dataSource); } return selectedDataSources; } /** * Adds a listener to receive notifications about explorer tree selection change. * * @param listener listener to add. */ public void addSelectionListener(ExplorerSelectionListener listener) { selectionListeners.add(listener); } /** * Removes explorer tree selection listener. * @param listener listener to remove. */ public void removeSelectionListener(ExplorerSelectionListener listener) { selectionListeners.remove(listener); } /** * Expands DataSource if displayed and collapsed in explorer tree. * * @param dataSource DataSource to expand. */ public void expandDataSource(DataSource dataSource) { expandNode(getNode(dataSource)); } void expandNode(final ExplorerNode node) { if (node == null) return; WindowManager.getDefault().invokeWhenUIReady(new Runnable() { public void run() { TreePath path = getPath(node); // For some reason expanding the path doesn't always work for a single invocation, // invoking twice to be sure mainTree.expandPath(path); mainTree.expandPath(path); } }); } /** * Collapses DataSource if displayed and expanded in explorer tree. * * @param dataSource DataSource to collapse. */ public void collapseDataSource(DataSource dataSource) { collapseNode(getNode(dataSource)); } void collapseNode(final ExplorerNode node) { if (node == null) return; WindowManager.getDefault().invokeWhenUIReady(new Runnable() { public void run() { mainTree.collapsePath(getPath(node)); } }); } /** * Adds a listener to receive notifications about expanded/collapsed explorer tree nodes. * * @param listener listener to add. */ public void addExpansionListener(ExplorerExpansionListener listener) { expansionListeners.add(listener); } /** * Removes explorer tree expansion listener. * * @param listener listener to remove. */ public void removeExpansionListener(ExplorerExpansionListener listener) { expansionListeners.remove(listener); } DataSource getDataSource(TreePath path) { if (path == null) return null; ExplorerNode node = (ExplorerNode)path.getLastPathComponent(); return node.getUserObject(); } ExplorerNode getNode(DataSource dataSource) { return ExplorerModelBuilder.getInstance().getNodeFor(dataSource); } TreePath getPath(ExplorerNode node) { return new TreePath(node.getPath()); } private ExplorerSupport() { WindowManager.getDefault().invokeWhenUIReady(new Runnable() { public void run() { mainTree = ExplorerComponent.instance().getTree(); mainTree.addTreeSelectionListener(new ExplorerTreeSelectionListener()); mainTree.addTreeExpansionListener(new ExplorerTreeExpansionListener()); } }); } private class ExplorerTreeSelectionListener implements TreeSelectionListener { public void valueChanged(TreeSelectionEvent e) { Set<DataSource> selectedDataSources = getSelectedDataSources(); Set<ExplorerSelectionListener> listeners = new HashSet(selectionListeners); for (ExplorerSelectionListener listener : listeners) listener.selectionChanged(selectedDataSources); } } private class ExplorerTreeExpansionListener implements TreeExpansionListener { public void treeExpanded(TreeExpansionEvent event) { DataSource expandedDataSource = getDataSource(event.getPath()); if (expandedDataSource != null) { Set<ExplorerExpansionListener> listeners = new HashSet(expansionListeners); for (ExplorerExpansionListener listener : listeners) listener.dataSourceExpanded(expandedDataSource); } } public void treeCollapsed(TreeExpansionEvent event) { DataSource collapsedDataSource = getDataSource(event.getPath()); if (collapsedDataSource != null) { Set<ExplorerExpansionListener> listeners = new HashSet(expansionListeners); for (ExplorerExpansionListener listener : listeners) listener.dataSourceCollapsed(collapsedDataSource); } } } }