package de.upbracing.gui.tabbed;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Enumeration;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;
/**
* This class extends JTabbedPane in the following way:
* - Tabs can now closeable, i.e. they have a X to close the tab
* - the add-methods are overridden
* - all add methods are overloaded with add(<old params>, boolean closeable),
* where <code>closeable</code> specifies the closeability of the added tab
*/
public class JCloseTabbedPane extends JTabbedPane{
private Color closeButtonStandardColor = Color.BLACK;
private Color closeButtonRolloverColor = Color.BLUE;
/**
* How the closeability of new tabs is determined:
* - ALL_CLOSEABLE, NONE_CLOSEABLE: all new tabs are closeable/non-closeable
* - MAIN_TAB: the first tab added (getTabCount()==0) is non-closeable,
* tabs that are added later are closeable. Default behaviour.
*
*/
public enum Behaviour{
MAIN_TAB, ALL_CLOSEABLE, NONE_CLOSEABLE
}
private Behaviour behaviour = Behaviour.NONE_CLOSEABLE;
public JCloseTabbedPane(int tabPlacement, int tabLayoutPolicy, Behaviour behaviour) {
super(tabPlacement, tabLayoutPolicy);
this.behaviour = behaviour;
}
public JCloseTabbedPane(int tabPlacement, Behaviour behaviour) {
super(tabPlacement);
this.behaviour = behaviour;
}
/**
* Changes the behavior of JCloseTabbedPane to the specified behavior.
* If behavior is not specified by the behavior constantsm, no change is
* made.
* @param behavior the new behavior
*/
public void setBehavior(Behaviour behavior) {
this.behaviour = behavior;
}
public JCloseTabbedPane(Behaviour behaviour)
{
super();
this.behaviour = behaviour;
}
/**
* Set the color for the Close Buttons for each tab
* @param color
*/
public void setCloseButtonColor(Color color)
{
closeButtonStandardColor = color;
}
/**
* Set the color for the Close Button when mouse is over for each tab.
* @param color
*/
public void setColoseButtonRolloverColor(Color color)
{
closeButtonRolloverColor=color;
}
/**
* The new tab's closeability is specified by the behaviour of
* JCloseTabbedPane.
* Further documentation about the add-method: JTabbedPane
*
* @see Behaviour
* @see JTabbedPane#add(Component)
*/
public Component add(Component component) {
switch (behaviour) {
case NONE_CLOSEABLE:
return add(component, false);
case ALL_CLOSEABLE:
return add(component, true);
case MAIN_TAB:
default:
return add(component,(getTabCount() != 0));
}
}
/**
* The new tab's closeability is specified by the behaviour of
* JCloseTabbedPane.
* Further documentation about the add-method: JTabbedPane
*
* @see Behaviour
* @see JTabbedPane#add(String, Component)
* @Override
*/
public Component add(String title, Component component) {
switch (behaviour) {
case ALL_CLOSEABLE:
return add(title, component, true);
case NONE_CLOSEABLE:
return add(title, component, false);
case MAIN_TAB:
default:
return add(title, component, (getTabCount() != 0));
}}
/**
* The new tab's closeability is specified by the behaviour of
* JCloseTabbedPane.
* Further documentation about the add-method: JTabbedPane
*
* @see Behaviour
* @see JTabbedPane.add(Component component, int index)
* @Override
*/
public Component add(Component component, int index) {
return add(component, index, (getTabCount() != 0));
}
/**
* The new tab's closeability is specified by the behaviour of
* JCloseTabbedPane.
* Further documentation about the add-method: JTabbedPane
*
* @see Behaviour
* @see JTabbedPane.add(Component component, Object constraints)
* @Override
*/
public void add(Component component, Object constraints) {
add(component, constraints, (getTabCount() != 0));
}
/**
* The new tab's closeability is specified by the behaviour of
* JCloseTabbedPane.
* Further documentation about the add-method: JTabbedPane
*
* @see Behaviour
* @see JTabbedPane.add(Component component, Object constraints, int index)
* @Override
*/
public void add(Component component, Object constraints, int index) {
add(component, constraints, index, (getTabCount() != 0));
}
/**
* The new tab is closeable, when the parameter <code>closeable</code> says
* so. Further documentation: JTabbedPane
*
*
* @see JTabbedPane.add(Component component)
*/
public Component add(Component component, boolean closeable) {
Component returnValue = super.add(component);
setNewestTabCloseable(closeable);
selectNewTab();
return returnValue;
}
/**
* The new tab is closeable, when the parameter <code>closeable</code> says
* so. Further documentation: JTabbedPane
*
*
* @see JTabbedPane.add(String title, Component component)
*/
public Component add(String title, Component component, boolean closeable) {
Component returnValue = super.add(title, component);
setNewestTabCloseable(closeable);
selectNewTab();
return returnValue;
}
/**
* The new tab is closeable, when the parameter <code>closeable</code> says
* so. Further documentation: JTabbedPane
*
*
* @see JTabbedPane.add(String title, Component component)
*/
public Component add(Component component, int index, boolean closeable) {
Component returnValue = super.add(component, index);
setNewestTabCloseable(closeable);
return returnValue;
}
/**
* The new tab is closeable, when the parameter <code>closeable</code> says
* so. Further documentation: JTabbedPane
*
*
* @see JTabbedPane.add(Component component, Object constraints)
*/
public void add(Component component, Object constraints, boolean closeable) {
super.add(component, constraints);
setNewestTabCloseable(closeable);
}
/**
* The new tab is closeable, when the parameter <code>closeable</code> says
* so. Further documentation: JTabbedPane
*
*
* @see JTabbedPane.add(Component component, Object constraints, int index)
*/
public void add(Component component, Object constraints, int index, boolean closeable) {
super.add(component, constraints, index);
setIsCloseableTab(index, closeable);
}
/**
* Selects the newest tab
*/
private void selectNewTab() {
setSelectedIndex(this.getTabCount()-1);
}
/**
* Sets the closeability of the newest tab to <code>closeable</code>.
* @param closeable true, if the newest tab should be closeable; false otherwise
*/
private void setNewestTabCloseable(boolean closeable) {
setIsCloseableTab(this.getTabCount()-1, closeable);
}
/**
* Sets the closeability of the tab at <code>index</code> to <code>closeable</code>.
* @param closeable true, if the tab should be closeable; false otherwise
* @param index the tab's index
*/
public void setIsCloseableTab(int index, boolean closeable) {
if(closeable)
setTabComponentAt(index, new ButtonTabComponent(this));
}
/**
* Documentation: JTabbedPane
*
*
* @see JTabbedPane#setTitleAt(int, String)
* @Override
*/
public void setTitle(int index, String title)
{
((ButtonTabComponent)this.getTabComponentAt(index)).setTitleLabel(title);
}
/**
* Private Class for the Close Button
*/
class ButtonTabComponent extends JPanel {
private final JTabbedPane pane;
private JLabel label;
private JButton button;
public ButtonTabComponent(final JTabbedPane pane) {
//unset default FlowLayout' gaps
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
if (pane == null) {
throw new NullPointerException("TabbedPane is null");
}
this.pane = pane;
setOpaque(false);
//make JLabel read titles from JTabbedPane
label = new JLabel() {
public String getText() {
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
if (i != -1) {
return pane.getTitleAt(i);
}
return null;
}
};
add(label);
//add more space between the label and the button
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
//tab button
button = new TabButton();
add(button);
//add more space to the top of the component
setBorder(BorderFactory.createEmptyBorder(2, 0, 0, 0));
}
public void setTitleLabel(String title)
{
label.setText(title);
}
private class TabButton extends JButton implements ActionListener {
public TabButton() {
int size = 17;
setPreferredSize(new Dimension(size, size));
setToolTipText("close this tab");
//Make the button looks the same for all Laf's
setUI(new BasicButtonUI());
//Make it transparent
setContentAreaFilled(false);
//No need to be focusable
setFocusable(false);
setBorder(BorderFactory.createEtchedBorder());
setBorderPainted(false);
//Making nice rollover effect
//we use the same listener for all buttons
addMouseListener(buttonMouseListener);
setRolloverEnabled(true);
//Close the proper tab by clicking the button
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
int i = pane.indexOfTabComponent(ButtonTabComponent.this);
if (i != -1) {
pane.remove(i);
}
}
//we don't want to update UI for this button
public void updateUI() {
}
//paint the cross
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
//shift the image for pressed buttons
if (getModel().isPressed()) {
g2.translate(1, 1);
}
g2.setStroke(new BasicStroke(2));
g2.setColor(JCloseTabbedPane.this.closeButtonStandardColor);
if (getModel().isRollover()) {
g2.setColor(JCloseTabbedPane.this.closeButtonRolloverColor);
}
int delta = 6;
g2.drawLine(delta, delta, getWidth() - delta - 1, getHeight() - delta - 1);
g2.drawLine(getWidth() - delta - 1, delta, delta, getHeight() - delta - 1);
g2.dispose();
}
}
// removed final static
private MouseListener buttonMouseListener = new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
Component component = e.getComponent();
if (component instanceof AbstractButton) {
AbstractButton button = (AbstractButton) component;
button.setBorderPainted(true);
}
}
public void mouseExited(MouseEvent e) {
Component component = e.getComponent();
if (component instanceof AbstractButton) {
AbstractButton button = (AbstractButton) component;
button.setBorderPainted(false);
}
}
};
}
}