/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.customcontrols;
/*
* The following code borrowed from David Bismut, davidou@mageos.com Intern,
* SETLabs, Infosys Technologies Ltd. May 2004 - Jul 2004 Ecole des Mines de
* Nantes, France
*/
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.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 net.java.sip.communicator.impl.gui.customcontrols.events.CloseListener;
import net.java.sip.communicator.impl.gui.customcontrols.events.DoubleClickListener;
import net.java.sip.communicator.impl.gui.customcontrols.events.MaxListener;
import net.java.sip.communicator.impl.gui.customcontrols.events.PopupOutsideListener;
import net.java.sip.communicator.impl.gui.lookandfeel.SIPCommTabbedPaneEnhancedUI;
import net.java.sip.communicator.impl.gui.lookandfeel.SIPCommTabbedPaneUI;
/**
* 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.
*
* @author Yana Stamcheva
*/
public class SIPCommTabbedPane extends JTabbedPane {
private int overTabIndex = -1;
/**
* Creates the CloseAndMaxTabbedPane
with an enhanced UI if
* enhancedUI
parameter is set to true
.
*
* @param enhancedUI
* whether the tabbedPane should use an enhanced UI
*/
public SIPCommTabbedPane(boolean enhancedUI) {
super.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
if (enhancedUI)
this.setUI(new SIPCommTabbedPaneEnhancedUI());
this.setMaxIcon(false);
}
/**
* 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() {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
return ui.isCloseEnabled();
}
/**
* Returns true
if the max/detach icon is enabled.
*/
public boolean isMaxEnabled() {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
return ui.isMaxEnabled();
}
/**
* Override JTabbedPane method. Does nothing.
* @param tabLayoutPolicy The tab layout policy.
*/
public void setTabLayoutPolicy(int tabLayoutPolicy) {
}
/**
* Override JTabbedPane method. Does nothing.
* @param tabPlacement The tab placement.
*/
public void setTabPlacement(int tabPlacement) {
}
/**
* 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) {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
ui.setCloseIcon(b);
}
/**
* Sets whether the tabbedPane should have a max/detach icon or not.
*
* @param b whether the tabbedPane should have a max/detach icon or not
*/
public void setMaxIcon(boolean b) {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
ui.setMaxIcon(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.show();
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
*/
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);
}
}
/**
* 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
*/
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
*/
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
*/
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);
}
}
/**
* Overrides setSelectedIndex in JTabbedPane in order to remove the
* hightlight if the tab which is selected.
* @param tabIndex The index of the tab to be selected.
*/
public void setSelectedIndex(int tabIndex) {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
if (ui.isTabHighlighted(tabIndex)) {
ui.tabRemoveHighlight(tabIndex);
}
super.setSelectedIndex(tabIndex);
}
/**
* Highlights the tab with the given index.
*
* @param tabIndex The tab index.
*/
public void highlightTab(int tabIndex) {
SIPCommTabbedPaneUI ui = (SIPCommTabbedPaneUI) this.getUI();
if (!ui.isTabHighlighted(tabIndex)
&& this.getSelectedIndex() != tabIndex)
ui.tabAddHightlight(tabIndex);
this.repaint();
}
}