/* * 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.ui; import com.sun.tools.visualvm.core.datasource.DataSource; import com.sun.tools.visualvm.core.datasource.descriptor.DataSourceDescriptorFactory; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingUtilities; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; /** * Class responsible for DataSourceViews manipulation. * * @author Jiri Sedlacek */ public final class DataSourceWindowManager { private static final RequestProcessor processor = new RequestProcessor("DataSourceWindowManager Processor"); // NOI18N private static final Logger LOGGER = Logger.getLogger(DataSourceWindowManager.class.getName()); private static DataSourceWindowManager sharedInstance; private final Map<DataSource, DataSourceWindow> openedWindows = Collections.synchronizedMap(new HashMap()); private final Map<DataSource, Set<DataSourceView>> openedViews = Collections.synchronizedMap(new HashMap()); /** * Returns singleton instance of DataSourceWindowManager. * * @return singleton instance of DataSourceWindowManager. */ public static synchronized DataSourceWindowManager sharedInstance() { if (sharedInstance == null) sharedInstance = new DataSourceWindowManager(); return sharedInstance; } /** * Returns true if there is at least one provider providing at least one view for given DataSource, false otherwise. * * @param dataSource DataSource to open. * @return true if there is at least one provider providing at least one view for given DataSource, false otherwise. */ public boolean canOpenDataSource(DataSource dataSource) { return DataSourceViewsManager.sharedInstance().hasViewsFor(dataSource); } /** * Opens the DataSource and selects the view. * * @param dataSource DataSource to open */ public void openDataSource(final DataSource dataSource) { openDataSource(dataSource, true); } /** * Opens the DataSource and optionally selects the view. * * @param dataSource DataSource to open * @param selectView true if the view should be selected, false otherwise */ public void openDataSource(final DataSource dataSource, final boolean selectView) { processor.post(new Runnable() { public void run() { openDataSource(dataSource, selectView, 0); } }); } /** * Opens the DataSource and optionally selects the view. * * @param dataSource DataSource to open * @param selectView true if the view should be selected, false otherwise * @param viewIndex index of the view to select * * @since VisualVM 1.3.9 */ public void openDataSource(final DataSource dataSource, final boolean selectView, final int viewIndex) { processor.post(new Runnable() { public void run() { openWindowAndAddView(dataSource, null, viewIndex, selectView, selectView, selectView); } }); } /** * Closes the DataSource. * * @param dataSource DataSource to close. */ public void closeDataSource(final DataSource dataSource) { processor.post(new Runnable() { public void run() { // Resolve viewmaster DataSource viewMaster = getViewMaster(dataSource); // Resolve cached window final DataSourceWindow window = openedWindows.get(viewMaster); if (window == null) return; // Window not opened if (dataSource == viewMaster) { SwingUtilities.invokeLater(new Runnable() { public void run() { window.removeAllViews(); } }); } else { // Remove all views of the dataSource Set<DataSourceView> views = openedViews.get(dataSource); if (views != null) { final Set<DataSourceView> viewsF = new HashSet(views); SwingUtilities.invokeLater(new Runnable() { public void run() { for (DataSourceView view : viewsF) if (window.containsView(view)) window.removeView(view); } }); } } } }); } /** * Opens the DataSource if needed and selects the DataSourceView. * * @param view DataSourceView to select. */ public void selectView(final DataSourceView view) { processor.post(new Runnable() { public void run() { openWindowAndAddView(view.getDataSource(), view, 0, true, true, true); } }); } private void openWindowAndAddView(DataSource dataSource, DataSourceView view, int viewIndex, final boolean selectView, final boolean selectWindow, final boolean windowToFront) { // Resolve viewmaster final DataSource viewMaster = getViewMaster(dataSource); // Resolve cached window final DataSourceWindow[] window = new DataSourceWindow[1]; window[0] = openedWindows.get(viewMaster); final boolean wasOpened = window[0] != null; final ProgressHandle pHandle = !wasOpened ? ProgressHandleFactory.createHandle(NbBundle.getMessage(DataSourceWindowManager.class, "LBL_Opening", // NOI18N DataSourceDescriptorFactory.getDescriptor(dataSource).getName())) : null; try { // Viewmaster's window not cached (opened), create if (!wasOpened) { // Setup progress pHandle.setInitialDelay(0); pHandle.start(); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { window[0] = new DataSourceWindow(viewMaster); } }); } catch (Exception e) { LOGGER.severe("Failed to create window for " + dataSource); // NOI18N } openedWindows.put(viewMaster, window[0]); List<? extends DataSourceView> views = DataSourceViewsManager.sharedInstance().getViews(viewMaster); addViews(window[0], views); } // Viewmaster opened, add views for the dataSource if (dataSource != viewMaster) { List<? extends DataSourceView> views = DataSourceViewsManager.sharedInstance().getViews(dataSource); addViews(window[0], views); if (selectView && view == null && viewIndex >= 0) { if (viewIndex >= views.size()) viewIndex = -1; if (viewIndex != -1) view = views.get(viewIndex); } } // Resolve view to select if (selectView && view == null && viewIndex > 0) { List<DataSourceView> views = window[0].getViews(); if (viewIndex >= views.size()) viewIndex = -1; if (viewIndex != -1) view = views.get(viewIndex); } // Open window final DataSourceView viewToSelectF = selectView ? view : null; SwingUtilities.invokeLater(new Runnable() { public void run() { if (viewToSelectF != null) { if (window[0].containsView(viewToSelectF)) { window[0].selectView(viewToSelectF); } else { if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning("Tried to select not opened view " + viewToSelectF); // NOI18N } } } if (!wasOpened) window[0].open(); if (selectWindow) window[0].requestActive(); if (windowToFront) window[0].toFront(); } }); } finally { SwingUtilities.invokeLater(new Runnable() { public void run() { if (pHandle != null) pHandle.finish(); } }); } } private DataSource getViewMaster(DataSource dataSource) { DataSource master = dataSource.getMaster(); while (master != null && master != DataSource.ROOT) { dataSource = master; master = dataSource.getMaster(); } return dataSource; } private <X extends DataSourceView> void addViews(final DataSourceWindow window, final List<X> views) { // Compute views to add final List<X> newViews = new ArrayList(); for (X view : views) if (!window.containsView(view)) newViews.add(view); // Blocking notification that the view will be added for (DataSourceView view : newViews) { try { DataSource dataSource = view.getDataSource(); Set<DataSourceView> cachedViews = openedViews.get(dataSource); if (cachedViews == null) { cachedViews = new HashSet(); openedViews.put(dataSource, cachedViews); } cachedViews.add(view); view.viewWillBeAdded(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to pre-initialize view " + view, e); // NOI18N } } try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { // Blocking adding of views to the window for (DataSourceView view : newViews) { try { window.addView(view); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to initialize view " + view, e); // NOI18N } } } }); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to initialize views for " + window.getDataSource(), e); // NOI18N } // Blocking notification that the view has been added for (DataSourceView view : newViews) { try { view.viewAdded(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Failed to post-initialize view " + view, e); // NOI18N } } } void unregisterClosedWindow(DataSourceWindow window) { openedWindows.remove(window.getDataSource()); } void unregisterClosedView(DataSourceView view) { DataSource dataSource = view.getDataSource(); Set<DataSourceView> views = openedViews.get(dataSource); if (views != null) { views.remove(view); if (views.isEmpty()) openedViews.remove(dataSource); } else if (LOGGER.isLoggable(Level.WARNING)) { LOGGER.warning("Tried to unregister not opened view " + view); // NOI18N } } private DataSourceWindowManager() {} }