/* * 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.components; import com.sun.tools.visualvm.core.datasupport.Positionable; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.openide.util.NbBundle; /** * * @author Jiri Sedlacek */ class DisplayArea extends JComponent { private boolean ignoresContentsHeight = true; DisplayArea() { initComponents(); setClosable(true); setVisible(false); // No tabs added yet } void setCaption(String caption) { this.caption = caption; if (presenter != null) presenter.setCaption(caption); } String getCaption() { return caption; } void setClosable(boolean closable) { optionsContainer.setClosable(closable); updatePresenter(); } boolean isClosable() { return optionsContainer.isClosable(); } void setIgnoresContentsHeight(boolean ignoresContentsHeight) { this.ignoresContentsHeight = ignoresContentsHeight; } boolean ignoresContentsHeight() { return ignoresContentsHeight; } Presenter getPresenter() { if (presenter == null) { presenter = createPresenter(); updatePresenter(); } return presenter; } void addTab(Tab tab) { final DisplayAreaSupport.TabButton tabButton = tabsContainer.addTab(tab); if (tabButton != null) { optionsContainer.addOptions(tab); updateTabbed(); if (tabsContainer.indexOfTab(tab) == 0) setSelectedTab(tab); final Tab tabF = tab; tabButton.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if (tabButton.isEnabled() && SwingUtilities.isLeftMouseButton(e)) setSelectedTab(tabF); } }); tabButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setSelectedTab(tabF); } }); } if (tabsContainer.getTabsCount() > 0) setVisible(true); updatePresenter(); } void removeTab(Tab tab) { Tab toSelect = null; boolean wasSelected = getSelectedTab() == tab; if (wasSelected) { toSelect = tabsContainer.getPreviousTab(tab); if (toSelect == null) toSelect = tabsContainer.getNextTab(tab); } if (tabsContainer.removeTab(tab)) { optionsContainer.removeOptions(tab); if (wasSelected) { if (toSelect != null) setSelectedTab(toSelect); else viewContainer.setSelectedView(null); } updateTabbed(); } if (tabsContainer.getTabsCount() == 0) setVisible(false); updatePresenter(); } boolean containsTab(Tab tab) { return tabsContainer.containsTab(tab); } void setSelectedTab(Tab tab) { if (tabsContainer.getSelectedTab() == tab) return; tabsContainer.setSelectedTab(tab); optionsContainer.setSelectedOptions(tab); viewContainer.setSelectedView(tab.getView()); } Tab getSelectedTab() { return tabsContainer.getSelectedTab(); } public Dimension getPreferredSize() { if (ignoresContentsHeight()) return new Dimension(0, tabsContainer.getPreferredSize().height); else return super.getPreferredSize(); } public Dimension getMinimumSize() { if (ignoresContentsHeight()) return getPreferredSize(); else return super.getMinimumSize(); } private void updatePresenter() { if (presenter == null) return; presenter.setVisible(tabsContainer.getTabsCount() > 0 && isClosable()); } private void updateTabbed() { boolean tabbed = tabsContainer.getTabsCount() > 1; middleSpacer.updateTabbed(tabbed); optionsContainer.updateTabbed(tabbed); } private Presenter createPresenter() { final Presenter presenter = new Presenter(); presenter.setCaption(caption); presenter.setOpaque(false); final boolean[] internalChange = new boolean[1]; internalChange[0] = false; presenter.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { internalChange[0] = true; setVisible(presenter.isSelected()); internalChange[0] = false; } }); addHierarchyListener(new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { boolean isShowing = isShowing(); presenter.setToolTipText(isShowing ? NbBundle.getMessage( DisplayArea.class, "ToolTip_HideSection", caption) : // NOI18N NbBundle.getMessage(DisplayArea.class, "ToolTip_ShowSection", caption)); // NOI18N if (!internalChange[0]) presenter.setSelected(isShowing); } } }); return presenter; } private void initComponents() { viewContainer = new ViewArea(); tabsContainer = new TabsContainer(); middleSpacer = new MiddleSpacer(); optionsContainer = new OptionsContainer(); JPanel captionArea = new JPanel(); captionArea.setLayout(new BorderLayout()); captionArea.setOpaque(false); captionArea.add(tabsContainer, BorderLayout.WEST); captionArea.add(middleSpacer, BorderLayout.CENTER); captionArea.add(optionsContainer, BorderLayout.EAST); setLayout(new BorderLayout()); add(captionArea, BorderLayout.NORTH); add(viewContainer, BorderLayout.CENTER); } private String caption = ""; // NOI18N private Presenter presenter; private ViewArea viewContainer; private TabsContainer tabsContainer; private MiddleSpacer middleSpacer; private OptionsContainer optionsContainer; static class Presenter extends JCheckBox { void setCaption(String caption) { setText(caption); } String getCaption() { return getText(); } void setDescription(String description) { setToolTipText(description); } String getDescription() { return getToolTipText(); } } static class Tab implements Positionable { private String name; private String description; private int preferredPosition; private JComponent view; private JComponent[] options; Tab(String name, JComponent view) { this(name, null, POSITION_AT_THE_END, view, null); } Tab(String name, String description, int preferredPosition, JComponent view, JComponent[] options) { setName(name); setDescription(description); setPreferredPosition(preferredPosition); setView(view); setOptions(options); } void setName(String name) { this.name = name; } String getName() { return name; } void setDescription(String description) { this.description = description; } String getDescription() { return description; } void setPreferredPosition(int preferredPosition) { this.preferredPosition = preferredPosition; } public int getPreferredPosition() { return preferredPosition; } void setView(JComponent view) { this.view = view; } JComponent getView() { return view; } void setOptions(JComponent[] options) { this.options = options != null ? options.clone() : null; } JComponent[] getOptions() { return options != null ? options.clone() : null; } } private static class TabsContainer extends JPanel { private List<Tab> tabs = new ArrayList(); private Tab selectedTab; private TabsContainer() { setLayout(null); setOpaque(true); setBackground(DisplayAreaSupport.BACKGROUND_COLOR_NORMAL); } private DisplayAreaSupport.TabButton addTab(Tab tab) { if (tabs.contains(tab)) return null; if (getLayout() == null) setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); tabs.add(tab); Collections.sort(tabs, Positionable.COMPARATOR); DisplayAreaSupport.TabButton tabButton = new DisplayAreaSupport.TabButton(tab.getName(), tab.getDescription()); DisplayAreaSupport.TabButtonContainer tabButtonContainer = new DisplayAreaSupport.TabButtonContainer(tabButton); tabButtonContainer.setAlignmentY(JComponent.TOP_ALIGNMENT); add(tabButtonContainer, tabs.indexOf(tab)); updateTabButtons(); return tabButton; } private int indexOfTab(Tab tab) { return tabs.indexOf(tab); } private boolean removeTab(Tab tab) { int index = indexOfTab(tab); if (index != -1) { tabs.remove(index); remove(index); if (tab == selectedTab) selectedTab = null; updateTabButtons(); return true; } return false; } private boolean containsTab(Tab tab) { return tabs.contains(tab); } private void setSelectedTab(Tab tab) { selectedTab = tab; updateTabButtons(); } private Tab getSelectedTab() { return selectedTab; } private Tab getPreviousTab(Tab tab) { int index = tabs.indexOf(tab); return index > 0 ? tabs.get(--index) : null; } private Tab getNextTab(Tab tab) { int index = tabs.indexOf(tab); return index < tabs.size() - 1 ? tabs.get(++index) : null; } private int getTabsCount() { return tabs.size(); } private void updateTabButtons() { int tabIndex = tabs.indexOf(selectedTab); Component[] components = getComponents(); int componentsCount = components.length; for (int i = 0; i < componentsCount; i++) ((DisplayAreaSupport.TabButtonContainer)components[i]).updateTabButton(i, tabIndex, componentsCount); } } private static class MiddleSpacer extends JPanel { private MiddleSpacer() { setLayout(null); setOpaque(true); setBackground(DisplayAreaSupport.BACKGROUND_COLOR_NORMAL); } private void updateTabbed(boolean tabbed) { if (tabbed) setBorder(DisplayAreaSupport.TabbedCaptionBorder.get( DisplayAreaSupport.BORDER_COLOR_NORMAL, DisplayAreaSupport.COLOR_NONE, DisplayAreaSupport.BORDER_COLOR_HIGHLIGHT, DisplayAreaSupport.COLOR_NONE)); else setBorder(DisplayAreaSupport.TabbedCaptionBorder.get( DisplayAreaSupport.BORDER_COLOR_NORMAL, DisplayAreaSupport.COLOR_NONE, DisplayAreaSupport.BACKGROUND_COLOR_NORMAL, DisplayAreaSupport.COLOR_NONE)); } } private static class OptionsContainer extends JPanel { private JPanel contentsPanel; private JButton closeButton; private CardLayout layout = new CardLayout(0, 0); private Map<Tab, JPanel> tabsMapper = new HashMap<Tab, JPanel>(); private OptionsContainer() { initComponents(); } private void setClosable(boolean closable) { closeButton.setVisible(closable); } private boolean isClosable() { return closeButton.isVisible(); } private void addOptions(Tab tab) { JPanel optionsContainer = new JPanel(); optionsContainer.setLayout(new BoxLayout(optionsContainer, BoxLayout.X_AXIS)); optionsContainer.setOpaque(false); JComponent[] options = tab.getOptions(); if (options != null) for (JComponent option : options) { option.setBorder(BorderFactory.createEmptyBorder(3, 5, 2, DisplayAreaSupport.TABBUTTON_MARGIN_RIGHT)); option.setAlignmentY(JComponent.CENTER_ALIGNMENT); optionsContainer.add(option); } tabsMapper.put(tab, optionsContainer); contentsPanel.add(optionsContainer, tab.getName()); } private void removeOptions(Tab tab) { JPanel optionsContainer = tabsMapper.remove(tab); if (optionsContainer != null) contentsPanel.remove(optionsContainer); } private void setSelectedOptions(Tab tab) { layout.show(contentsPanel, tab.getName()); } private void updateTabbed(boolean tabbed) { if (tabbed) setBorder(DisplayAreaSupport.TabbedCaptionBorder.get( DisplayAreaSupport.BORDER_COLOR_NORMAL, DisplayAreaSupport.COLOR_NONE, DisplayAreaSupport.BORDER_COLOR_HIGHLIGHT, DisplayAreaSupport.BORDER_COLOR_NORMAL)); else setBorder(DisplayAreaSupport.TabbedCaptionBorder.get( DisplayAreaSupport.BORDER_COLOR_NORMAL, DisplayAreaSupport.COLOR_NONE, DisplayAreaSupport.COLOR_NONE, DisplayAreaSupport.BORDER_COLOR_NORMAL)); } private void initComponents() { setLayout(new BorderLayout()); setOpaque(true); setBackground(DisplayAreaSupport.BACKGROUND_COLOR_NORMAL); ImageIcon closeIcon = new ImageIcon(DisplayArea.class.getResource("/com/sun/tools/visualvm/core/ui/resources/closePanel.png")); // NOI18N closeButton = new DisplayAreaSupport.ImageIconButton(closeIcon); closeButton.setToolTipText(NbBundle.getMessage(DisplayArea.class, "ToolTip_Hide")); // NOI18N closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { getParent().getParent().setVisible(false); } }); contentsPanel = new JPanel(layout); contentsPanel.setOpaque(false); add(contentsPanel, BorderLayout.WEST); add(closeButton, BorderLayout.EAST); } } private static class ViewArea extends JPanel { private ViewArea() { setLayout(new BorderLayout()); setOpaque(false); } private void setSelectedView(JComponent component) { synchronized (getTreeLock()) { removeAll(); if (component != null) add(component, BorderLayout.CENTER); revalidate(); repaint(); } } } }