/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package genius.gui.panels.tab;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.io.Serializable;
import java.util.EventListener;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.EventListenerList;
import javax.swing.plaf.TabbedPaneUI;
/**
* A JTabbedPane with some added UI functionalities. A close and max/detach
* icons are added to every tab, typically to let the user close or detach the
* tab by clicking on these icons.
*
* @version 1.1 06/07/04
* @author David Bismut, davidou@mageos.com
*/
public class CloseTabbedPane extends JTabbedPane implements Serializable {
private static final long serialVersionUID = -819489825604971110L;
private int overTabIndex = -1;
private CloseTabPaneUI paneUI;
// private CloseTabProxyUI paneUI;
/**
* Creates the CloseAndMaxTabbedPane
with an enhanced UI if
* enhancedUI
parameter is set to true
.
*/
public CloseTabbedPane() {
super.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
paneUI = new CloseTabPaneEnhancedUI();
// paneUI = (CloseTabProxyUI) CloseTabProxyUI.createUI(this);//new
// CloseTabProxyUI((TabbedPaneUI)UIManager.getUI(this));
super.setUI(paneUI);
}
/**
* Returns the index of the last tab on which the mouse did an action.
*/
public int getOverTabIndex() {
return overTabIndex;
}
/**
* Returns true
if the close icon is enabled.
*/
public boolean isCloseEnabled() {
return paneUI.isCloseEnabled();
}
/**
* Override JTabbedPane method. Does nothing.
*/
public void setTabLayoutPolicy(int tabLayoutPolicy) {
}
/**
* Override JTabbedPane method. Does nothing.
*/
public void setTabPlacement(int tabPlacement) {
}
/**
* Override JTabbedPane method. Does nothing.
*/
public void setUI(TabbedPaneUI ui) {
}
/**
* Sets whether the tabbedPane should have a close icon or not.
*
* @param b
* whether the tabbedPane should have a close icon or not
*/
public void setCloseIcon(boolean b) {
paneUI.setCloseIcon(b);
}
/**
* Detaches the index
tab in a seperate frame. When the frame
* is closed, the tab is automatically reinserted into the tabbedPane.
*
* @param index
* index of the tabbedPane to be detached
*/
public void detachTab(int index) {
if (index < 0 || index >= getTabCount())
return;
final JFrame frame = new JFrame();
Window parentWindow = SwingUtilities.windowForComponent(this);
final int tabIndex = index;
final JComponent c = (JComponent) getComponentAt(tabIndex);
final Icon icon = getIconAt(tabIndex);
final String title = getTitleAt(tabIndex);
final String toolTip = getToolTipTextAt(tabIndex);
final Border border = c.getBorder();
removeTabAt(index);
c.setPreferredSize(c.getSize());
frame.setTitle(title);
frame.getContentPane().add(c);
frame.setLocation(parentWindow.getLocation());
frame.pack();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent event) {
frame.dispose();
insertTab(title, icon, c, toolTip,
Math.min(tabIndex, getTabCount()));
c.setBorder(border);
setSelectedComponent(c);
}
});
WindowFocusListener windowFocusListener = new WindowFocusListener() {
long start;
long end;
public void windowGainedFocus(WindowEvent e) {
start = System.currentTimeMillis();
}
public void windowLostFocus(WindowEvent e) {
end = System.currentTimeMillis();
long elapsed = end - start;
// System.out.println(elapsed);
if (elapsed < 100)
frame.toFront();
frame.removeWindowFocusListener(this);
}
};
/*
* This is a small hack to avoid Windows GUI bug, that prevent a new
* window from stealing focus (without this windowFocusListener, most of
* the time the new frame would just blink from foreground to
* background). A windowFocusListener is added to the frame, and if the
* time between the frame beeing in foreground and the frame beeing in
* background is less that 100ms, it just brings the windows to the
* front once again. Then it removes the windowFocusListener. Note that
* this hack would not be required on Linux or UNIX based systems.
*/
frame.addWindowFocusListener(windowFocusListener);
frame.setVisible(true);
frame.toFront();
}
/**
* Adds a CloseListener
to the tabbedPane.
*
* @param l
* the CloseListener
to add
* @see #fireCloseTabEvent
* @see #removeCloseListener
*/
public synchronized void addCloseListener(CloseListener l) {
listenerList.add(CloseListener.class, l);
}
/**
* Adds a MaxListener
to the tabbedPane.
*
* @param l
* the MaxListener
to add
* @see #fireMaxTabEvent
* @see #removeMaxListener
*/
public synchronized void addMaxListener(MaxListener l) {
listenerList.add(MaxListener.class, l);
}
/**
* Adds a DoubleClickListener
to the tabbedPane.
*
* @param l
* the DoubleClickListener
to add
* @see #fireDoubleClickTabEvent
* @see #removeDoubleClickListener
*/
public synchronized void addDoubleClickListener(DoubleClickListener l) {
listenerList.add(DoubleClickListener.class, l);
}
/**
* Adds a PopupOutsideListener
to the tabbedPane.
*
* @param l
* the PopupOutsideListener
to add
* @see #firePopupOutsideTabEvent
* @see #removePopupOutsideListener
*/
public synchronized void addPopupOutsideListener(PopupOutsideListener l) {
listenerList.add(PopupOutsideListener.class, l);
}
/**
* Removes a CloseListener
from this tabbedPane.
*
* @param l
* the CloseListener
to remove
* @see #fireCloseTabEvent
* @see #addCloseListener
*/
public synchronized void removeCloseListener(CloseListener l) {
listenerList.remove(CloseListener.class, l);
}
/**
* Removes a MaxListener
from this tabbedPane.
*
* @param l
* the MaxListener
to remove
* @see #fireMaxTabEvent
* @see #addMaxListener
*/
public synchronized void removeMaxListener(MaxListener l) {
listenerList.remove(MaxListener.class, l);
}
/**
* Removes a DoubleClickListener
from this tabbedPane.
*
* @param l
* the DoubleClickListener
to remove
* @see #fireDoubleClickTabEvent
* @see #addDoubleClickListener
*/
public synchronized void removeDoubleClickListener(DoubleClickListener l) {
listenerList.remove(DoubleClickListener.class, l);
}
/**
* Removes a PopupOutsideListener
from this tabbedPane.
*
* @param l
* the PopupOutsideListener
to remove
* @see #firePopupOutsideTabEvent
* @see #addPopupOutsideListener
*/
public synchronized void removePopupOutsideListener(PopupOutsideListener l) {
listenerList.remove(PopupOutsideListener.class, l);
}
/**
* Sends a MouseEvent
, whose source is this tabbedpane, to
* every CloseListener
. The method also updates the
* overTabIndex
of the tabbedPane with a value coming from the
* UI. This method method is called each time a MouseEvent
is
* received from the UI when the user clicks on the close icon of the tab
* which index is overTabIndex
.
*
* @param e
* the MouseEvent
to be sent
* @param overTabIndex
* the index of a tab, usually the tab over which the mouse is
*
* @see #addCloseListener
* @see EventListenerList
*/
public void fireCloseTabEvent(MouseEvent e, int overTabIndex) {
this.overTabIndex = overTabIndex;
EventListener closeListeners[] = getListeners(CloseListener.class);
for (int i = 0; i < closeListeners.length; i++) {
((CloseListener) closeListeners[i]).closeOperation(e, overTabIndex);
}
}
/**
* Sends a MouseEvent
, whose source is this tabbedpane, to
* every MaxListener
. The method also updates the
* overTabIndex
of the tabbedPane with a value coming from the
* UI. This method method is called each time a MouseEvent
is
* received from the UI when the user clicks on the max icon of the tab
* which index is overTabIndex
.
*
* @param e
* the MouseEvent
to be sent
* @param overTabIndex
* the index of a tab, usually the tab over which the mouse is
*
* @see #addMaxListener
* @see EventListenerList
*/
public void fireMaxTabEvent(MouseEvent e, int overTabIndex) {
this.overTabIndex = overTabIndex;
EventListener maxListeners[] = getListeners(MaxListener.class);
for (int i = 0; i < maxListeners.length; i++) {
((MaxListener) maxListeners[i]).maxOperation(e);
}
}
/**
* Sends a MouseEvent
, whose source is this tabbedpane, to
* every DoubleClickListener
. The method also updates the
* overTabIndex
of the tabbedPane with a value coming from the
* UI. This method method is called each time a MouseEvent
is
* received from the UI when the user double-clicks on the tab which index
* is overTabIndex
.
*
* @param e
* the MouseEvent
to be sent
* @param overTabIndex
* the index of a tab, usually the tab over which the mouse is
*
* @see #addDoubleClickListener
* @see EventListenerList
*/
public void fireDoubleClickTabEvent(MouseEvent e, int overTabIndex) {
this.overTabIndex = overTabIndex;
EventListener dClickListeners[] = getListeners(DoubleClickListener.class);
for (int i = 0; i < dClickListeners.length; i++) {
((DoubleClickListener) dClickListeners[i]).doubleClickOperation(e);
}
}
/**
* Sends a MouseEvent
, whose source is this tabbedpane, to
* every PopupOutsideListener
. The method also sets the
* overTabIndex
to -1. This method method is called each time a
* MouseEvent
is received from the UI when the user
* right-clicks on the inactive part of a tabbedPane.
*
* @param e
* the MouseEvent
to be sent
*
* @see #addPopupOutsideListener
* @see EventListenerList
*/
public void firePopupOutsideTabEvent(MouseEvent e) {
this.overTabIndex = -1;
EventListener popupListeners[] = getListeners(PopupOutsideListener.class);
for (int i = 0; i < popupListeners.length; i++) {
((PopupOutsideListener) popupListeners[i]).popupOutsideOperation(e);
}
}
}