/*
* 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();
}
}
}
}