// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/gui/dock/DockWrapper.java,v $
// $RCSfile: DockWrapper.java,v $
// $Revision: 1.7 $
// $Date: 2005/08/09 17:50:51 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.gui.dock;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ButtonUI;
import com.bbn.openmap.util.Debug;
/**
* A panel that contains controls that will either be docked,
* internal-framed or external framed...
*
* @author Ben Lubin
* @version $Revision: 1.7 $ on $Date: 2005/08/09 17:50:51 $
* @since 12/5/02
*/
public class DockWrapper extends JPanel {
/* package */static final int UNDEF = -1;
/* package */static final int EXTERNAL = 1;
/* package */static final int INTERNAL = 2;
/* package */static final int DOCK_NORTH = 3;
/* package */static final int DOCK_SOUTH = 4;
/* package */static final int DOCK_WEST = 5;
/* package */static final int DOCK_EAST = 6;
/** Is this wrapper currently resizable? */
private boolean resizable = false;
/** Which docking state we are in */
private int state = UNDEF;
/** are we transparent? */
private boolean transparent = false;
/** Holds the tabbed pane if we are currently holding tabs. */
private JTabbedPane tabPane = null;
BasicDockPanel dockPanel;
/** Contents of this wrapper, size >1 if tabbed, 1 if not tabbed. */
private List children = new ArrayList(1);
/** Other Wrappers that have been docked onto this one. */
private List dockedWrappers = new ArrayList(0);
private MouseHandler mouseHandler = new MouseHandler();
public DockWrapper(BasicDockPanel dp) {
dockPanel = dp;
setLayout(new BorderLayout());
setOpaque(false);
}
/** Special constructor for use in the cardinal DockWrappers */
/* package */DockWrapper(BasicDockPanel dp, int state) {
this(dp);
this.state = state;
}
//Accessor Methods:
///////////////////
public void addChild(JComponent child) {
children.add(child);
if (isTabbed()) {
String tabName = dockPanel.getConstraint(child).getTabName();
if (tabName == null) {
tabName = child.getName();
}
tabPane.insertTab(tabName, null, child, null, 0);
} else {
add(child, BorderLayout.CENTER);
}
}
public void removeChild(JComponent child) {
if (children.size() < 1) {
Debug.error("DockWrapper: Unexpected children list");
}
if (isTabbed()) {
tabPane.remove(child);
} else {
remove(child);
}
children.remove(child);
}
/**
* Get all of the children that we are holding. The returned list
* will have one element iff the DockWrapper is not tabbed.
*
* @return a list of JComponents that are the children.
*/
public List getChildren() {
return children;
}
/**
* Get the one and only child if we are not tabbed. If we are
* tabbed, there may be more than one child...
*/
public JComponent getChild() {
return (children.isEmpty() ? null : (JComponent) children.get(0));
}
//Tabbing Methods:
//////////////////
/* package */void setTabName(JComponent child, String name) {
if (isTabbed()) {
tabPane.setTitleAt(tabPane.indexOfComponent(child), name);
}
}
/** Returns true iff this dockable contains more than one component */
public boolean isTabbed() {
return tabPane != null;
}
/**
* Get the index of the dockwrapper that we should use for
* tabbing-up, or -1 if there is none.
*/
public int getDockedWrapperIndexForTabbing() {
int idx = 0;
for (Iterator iter = getDockedWrappers().iterator(); iter.hasNext();) {
DockWrapper dw = (DockWrapper) iter.next();
if (dw.canTab()) {
return idx;
}
idx++;
}
return -1;
}
private void tab(DockWrapper w) {
//Get rid of the existing wrapper:
dockPanel.removeWrapper(w);
if (children.size() == 1) {
//Create the tab pane:
JComponent child = getChild();
removeChild(child);
tabPane = new JTabbedPane(JTabbedPane.BOTTOM);
add(tabPane, BorderLayout.CENTER);
setOpaque(true);
addChild(child);
}
for (Iterator iter = w.getChildren().iterator(); iter.hasNext();) {
JComponent child = (JComponent) iter.next();
dockPanel.setWrapper(child, this);
addChild(child);
}
}
// private void untab(JComponent child) {
// if (child == null) {
// throw new RuntimeException("Can't untab null");
// }
// removeChild(child);
// if (children.size() == 1) {
// JComponent curChild = getChild();
// removeChild(curChild);
// remove(tabPane);
// tabPane = null;
// addChild(curChild);
// setOpaque(false);
// }
// DockWrapper dw = dockPanel.createDockWrapper(child);
// }
//Transparency Methods:
///////////////////////
public void doLayout() {
updateTransparency();
super.doLayout();
}
/**
* Set the indicated JComponent to transparent or not transparent.
*
* @return true iff this call has changed the state
*/
protected static boolean setTransparent(JComponent child, boolean t) {
boolean ret = false;
if (child instanceof JPanel) {
child.setOpaque(!t);
ret |= child.isOpaque() == t;
}
if (child instanceof JToolBar) {
child.setOpaque(!t);
ret |= child.isOpaque() == t;
}
if (child instanceof AbstractButton) {
AbstractButton b = (AbstractButton) child;
if (t) {
if (!(b.getUI() instanceof TransparentButtonUI)) {
b.setContentAreaFilled(false);
b.setUI((ButtonUI) TransparentButtonUI.createUI(b));
ret = true;
}
} else {
if (b.getUI() instanceof TransparentButtonUI) {
b.setContentAreaFilled(true);
b.setUI((ButtonUI) UIManager.getUI(b));
ret = true;
}
}
}
for (int i = 0; i < child.getComponentCount(); i++) {
Object o = child.getComponent(i);
if (o instanceof JComponent) {
JComponent c = (JComponent) o;
ret |= setTransparent(c, t);
}
}
return ret;
}
//Resizing Methods:
///////////////////
protected void makeNotResizable() {
setBorder(null);
removeMouseListener(mouseHandler);
removeMouseMotionListener(mouseHandler);
}
protected void makeResizable() {
setBorder(makeResizeBorder());
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
/** get the border that mouse is in */
protected int inBorder(int x, int y) {
Border b = getBorder();
if (b == null) {
return UNDEF;
}
Insets i = b.getBorderInsets(this);
if (x <= i.left) {
return DOCK_WEST;
}
if (x >= getWidth() - i.right) {
return DOCK_EAST;
}
if (y <= i.top) {
return DOCK_NORTH;
}
if (y >= getHeight() - i.bottom) {
return DOCK_SOUTH;
}
return UNDEF;
}
protected Border makeResizeBorder() {
Color highlightOuter = UIManager.getColor("controlLtHighlight");
Color highlightInner = UIManager.getColor("controlHighlight");
Color shadowOuter = UIManager.getColor("controlDkShadow");
Color shadowInner = UIManager.getColor("controlShadow");
if (transparent) {
highlightOuter = new Color(0, 0, 0, 50);
highlightInner = new Color(0, 0, 0, 75);
shadowOuter = new Color(0, 0, 0, 175);
shadowInner = new Color(0, 0, 0, 150);
}
Border border = BorderFactory.createCompoundBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED,
highlightOuter,
highlightInner,
shadowOuter,
shadowInner),
BorderFactory.createBevelBorder(BevelBorder.LOWERED,
highlightOuter,
highlightInner,
shadowOuter,
shadowInner));
return border;
}
//Constraint methods:
/////////////////////
/**
* Set the transparency of this DockWrapper to whatever the
* Constraint says it should be.
*
* @return true iff the state has changed.
*/
public boolean updateTransparency() {
boolean ret = false;
if (children.size() == 1) {
boolean t = dockPanel.getConstraint(getChild()).canTransparent();
transparent = t;
ret |= setTransparent(getChild(), t);
} else {
transparent = false;
for (Iterator iter = children.iterator(); iter.hasNext();) {
JComponent c = (JComponent) iter.next();
ret |= setTransparent(c, transparent);
}
}
return ret;
}
/** Make the dock wrapper's border reflect its resizability */
public void updateResizable() {
List constraints = dockPanel.getConstraints(getChildren());
boolean canResize = DockConstraint.canResize(constraints);
if (resizable && !canResize) {
makeNotResizable();
}
if (!resizable && canResize) {
makeResizable();
}
}
/** Determine if this can occlude */
public boolean canOcclude() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canOcclude(constraints);
}
/** Determine if this can tab */
public boolean canTab() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canTab(constraints);
}
/** Determine if this can close */
public boolean canClose() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canClose(constraints);
}
/** Determine if this can internalFrame */
public boolean canInternalFrame() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canInternalFrame(constraints);
}
/** Determine if this can externalFrame */
public boolean canExternalFrame() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canExternalFrame(constraints);
}
/** Determine if this can dockNorth */
public boolean canDockNorth() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canDockNorth(constraints);
}
/** Determine if this can dockSouth */
public boolean canDockSouth() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canDockSouth(constraints);
}
/** Determine if this can dockEast */
public boolean canDockEast() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canDockEast(constraints);
}
/** Determine if this can dockWest */
public boolean canDockWest() {
List constraints = dockPanel.getConstraints(getChildren());
return DockConstraint.canDockWest(constraints);
}
//State Methods:
////////////////
public void makeExternalFrame() {
freeWrapper();
state = EXTERNAL;
}
protected void removeExternalFrame() {
state = UNDEF;
}
public void makeInternalFrame() {
freeWrapper();
state = INTERNAL;
}
protected void removeInternalFrame() {
state = UNDEF;
}
public void makeDockNorth() {
makeDock(DOCK_NORTH);
}
protected void removeDockNorth() {
removeDock();
}
public void makeDockSouth() {
makeDock(DOCK_SOUTH);
}
protected void removeDockSouth() {
removeDock();
}
public void makeDockEast() {
makeDock(DOCK_EAST);
}
protected void removeDockEast() {
removeDock();
}
public void makeDockWest() {
makeDock(DOCK_WEST);
}
protected void removeDockWest() {
removeDock();
}
protected void makeDock(int state) {
freeWrapper();
this.state = state;
dockPanel.addDockWrapper(this);
orientToolbars();
}
protected void orientToolbars() {
for (Iterator iter = getChildren().iterator(); iter.hasNext();) {
JComponent child = (JComponent) iter.next();
if (!(child instanceof JToolBar)) {
continue;
}
JToolBar t = (JToolBar) child;
switch (state) {
case DOCK_NORTH:
case DOCK_SOUTH:
t.setOrientation(JToolBar.HORIZONTAL);
break;
case DOCK_EAST:
case DOCK_WEST:
t.setOrientation(JToolBar.VERTICAL);
break;
}
}
}
protected void removeDock() {
dockPanel.removeDockWrapper(this);
this.state = UNDEF;
}
protected void setState(int state) {
switch (state) {
case INTERNAL:
makeInternalFrame();
break;
case EXTERNAL:
makeExternalFrame();
break;
case DOCK_NORTH:
makeDockNorth();
break;
case DOCK_SOUTH:
makeDockSouth();
break;
case DOCK_WEST:
makeDockWest();
break;
case DOCK_EAST:
makeDockEast();
break;
}
}
//Docking up Methods:
/////////////////////
public void freeWrapper() {
switch (state) {
case INTERNAL:
removeInternalFrame();
break;
case EXTERNAL:
removeExternalFrame();
break;
case DOCK_NORTH:
removeDockNorth();
break;
case DOCK_SOUTH:
removeDockSouth();
break;
case DOCK_WEST:
removeDockWest();
break;
case DOCK_EAST:
removeDockEast();
break;
}
}
/** Attempt to remove the given wrapper from us */
public boolean freeWrapper(DockWrapper w) {
if (dockedWrappers.remove(w)) {
w.freeWrapper();
return true;
}
for (Iterator iter = dockedWrappers.iterator(); iter.hasNext();) {
DockWrapper dw = (DockWrapper) iter.next();
if (dw.freeWrapper(w)) {
return true;
}
}
return false;
}
public boolean hasDockedWrappers() {
return !getDockedWrappers().isEmpty();
}
public List getDockedWrappers() {
return dockedWrappers;
}
public DockWrapper getDockedWrapper(int idx) {
return (DockWrapper) dockedWrappers.get(idx);
}
public void dock(DockWrapper w) {
dock(w, -1);
}
public void dock(DockWrapper w, int i) {
w.setState(state);
int idx = getDockedWrapperIndexForTabbing();
if (idx != -1 && w.canTab()) {
getDockedWrapper(idx).tab(w);
} else {
if (i == -1) {
dockedWrappers.add(w);
} else {
dockedWrappers.set(i, w);
}
}
}
/**
* Recursively determine if another wrapper is docked on this one.
*/
public boolean isDockedOnRecurse(DockWrapper w) {
if (this.equals(w)) {
return true;
}
for (Iterator iter = dockedWrappers.iterator(); iter.hasNext();) {
DockWrapper dw = (DockWrapper) iter.next();
if (dw.isDockedOnRecurse(w)) {
return true;
}
}
return false;
}
public void setPreferredHeight(int i) {
Dimension d = getPreferredSize();
d.height = i;
setPreferredSize(d);
}
public void setPreferredWidth(int i) {
Dimension d = getPreferredSize();
d.width = i;
setPreferredSize(d);
}
//Nested Classes:
/////////////////
protected class MouseHandler extends MouseInputAdapter {
int resizeLoc = UNDEF;
int pressedVal = 0;
public void mousePressed(MouseEvent e) {
resizeLoc = inBorder(e.getX(), e.getY());
switch (resizeLoc) {
case DOCK_NORTH:
case DOCK_SOUTH:
pressedVal = e.getY();
break;
case DOCK_EAST:
case DOCK_WEST:
pressedVal = e.getX();
break;
}
}
public void mouseReleased(MouseEvent e) {
Dimension d = getSize();
switch (resizeLoc) {
case DOCK_NORTH:
d.height += pressedVal - e.getY();
setPreferredSize(d);
revalidate();
break;
case DOCK_SOUTH:
d.height -= pressedVal - e.getY();
setPreferredSize(d);
revalidate();
break;
case DOCK_EAST:
d.width -= pressedVal - e.getX();
setPreferredSize(d);
revalidate();
break;
case DOCK_WEST:
d.width += pressedVal - e.getX();
setPreferredSize(d);
revalidate();
break;
}
}
public void mouseMoved(MouseEvent e) {
int loc = inBorder(e.getX(), e.getY());
switch (loc) {
case DOCK_NORTH:
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
break;
case DOCK_SOUTH:
setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
break;
case DOCK_EAST:
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
break;
case DOCK_WEST:
setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
break;
default:
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
public void mouseExited(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}