0001: /*
0002: * Copyright (C) 2004 NNL Technology AB
0003: * Visit www.infonode.net for information about InfoNode(R)
0004: * products and how to contact NNL Technology AB.
0005: *
0006: * This program is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU General Public License
0008: * as published by the Free Software Foundation; either version 2
0009: * of the License, or (at your option) any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: * GNU General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with this program; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
0019: * MA 02111-1307, USA.
0020: */
0021:
0022: // $Id: TabbedPanel.java,v 1.167 2005/12/04 13:46:05 jesper Exp $
0023: package net.infonode.tabbedpanel;
0024:
0025: import net.infonode.gui.*;
0026: import net.infonode.gui.draggable.*;
0027: import net.infonode.gui.hover.HoverEvent;
0028: import net.infonode.gui.hover.HoverListener;
0029: import net.infonode.gui.hover.panel.HoverableShapedPanel;
0030: import net.infonode.gui.layout.DirectionLayout;
0031: import net.infonode.gui.panel.BaseContainerUtil;
0032: import net.infonode.gui.shaped.panel.ShapedPanel;
0033: import net.infonode.properties.gui.InternalPropertiesUtil;
0034: import net.infonode.properties.gui.util.ButtonProperties;
0035: import net.infonode.properties.gui.util.ComponentProperties;
0036: import net.infonode.properties.gui.util.ShapedPanelProperties;
0037: import net.infonode.properties.propertymap.PropertyMap;
0038: import net.infonode.properties.propertymap.PropertyMapTreeListener;
0039: import net.infonode.properties.propertymap.PropertyMapWeakListenerManager;
0040: import net.infonode.tabbedpanel.internal.ShadowPainter;
0041: import net.infonode.tabbedpanel.internal.TabDropDownList;
0042: import net.infonode.tabbedpanel.internal.TabbedHoverUtil;
0043: import net.infonode.tabbedpanel.titledtab.TitledTab;
0044: import net.infonode.util.Direction;
0045: import net.infonode.util.ValueChange;
0046:
0047: import javax.swing.*;
0048: import javax.swing.border.Border;
0049: import javax.swing.border.CompoundBorder;
0050: import javax.swing.border.EmptyBorder;
0051: import java.awt.*;
0052: import java.awt.event.MouseEvent;
0053: import java.util.ArrayList;
0054: import java.util.Map;
0055: import java.util.Set;
0056:
0057: /**
0058: * <p>
0059: * A TabbedPanel is a component that handles a group of components in a notebook
0060: * like manor. Each component is represented by a {@link Tab}. A tab is a
0061: * component itself that defines how the tab will be rendered. The tab also
0062: * holds a reference to the content component associated with the tab. The
0063: * tabbed panel is divided into two areas, the tab area where the tabs are
0064: * displayed and the content area where the tab's content component is
0065: * displayed.
0066: * </p>
0067: *
0068: * <p>
0069: * The demo program for InfoNode Tabbed Panel on
0070: * <a href="http://www.infonode.net/index.html?itpdemo" target="_blank">
0071: * www.infonode.net</a> demonstrates and explains most of the tabbed panel's
0072: * features.
0073: * </p>
0074: *
0075: * <p>
0076: * The tabbed panel is configured using a {@link TabbedPanelProperties} object.
0077: * A tabbed panel will always have a properties object with default values based
0078: * on the current Look and Feel
0079: * </p>
0080: *
0081: * <p>
0082: * Tabs can be added, inserted, removed, selected, highlighted, dragged and
0083: * moved.
0084: * </p>
0085: *
0086: * <p>
0087: * The tabbed panel support tab placement in a horizontal line above or under
0088: * the content area or a vertical row to the left or to the right of the content
0089: * area. The tab line can be laid out as either scrolling or compression. If the
0090: * tabs are too many to fit in the tab area and scrolling is enabled, then the
0091: * mouse wheel is activated and scrollbuttons are shown so that the tabs can be
0092: * scrolled. Compression means that the tabs will be downsized to fit into the
0093: * visible tab area.
0094: * </p>
0095: *
0096: * <p>
0097: * It is possible to display a button in the tab area next to the tabs that shows
0098: * a drop down list (called tab drop down list) with all the tabs where it is
0099: * possible to select a tab. This is for example useful when the tabbed panel
0100: * contains a large amount of tabs or if some tabs are scrolled out. The drop down
0101: * list can show a text and an icon for a tab. The text is retrieved by calling
0102: * toString() on the tab and the icon is only retrieved if the tab implements the
0103: * {@link net.infonode.gui.icon.IconProvider} interface.
0104: * </p>
0105: *
0106: * <p>
0107: * It is possible to set an array of components (called tab area components) to
0108: * be shown next to the tabs in the tab area, the same place where the drop down
0109: * list and the scrollbuttons are shown. This for example useful for adding
0110: * buttons to the tabbed panel.
0111: * </p>
0112: *
0113: * <p>
0114: * It is possible to add a {@link TabListener} and receive events when a tab is
0115: * added, removed, selected, deselected, highlighted, dehighlighted, moved,
0116: * dragged, dropped or drag is aborted. The listener will receive events for all
0117: * the tabs in the tabbed panel. A tabbed panel will trigger selected,
0118: * deselected, highlighted and dehighlighted even if for example the selected
0119: * tab is null (no selected tab), i.e. null will be treated as if it was a tab.
0120: * </p>
0121: *
0122: * <p>
0123: * A tabbed panel supports several mouse hover alternatives. It is possible to
0124: * specify {@link HoverListener}s for the entire tabbed panel, the tab area, the
0125: * tab area components area and the content area. The listeners are set in the
0126: * TabbedPanelProperties, TabAreaProperties, TabAreaComponentsProperties and the
0127: * TabbedPanelContentPanelProperties. A hover listener is called when the mouse
0128: * enter or exits the area. The hover listener is called with a {@link HoverEvent}
0129: * and the source for the event is always the hovered tabbed panel.
0130: * </p>
0131: *
0132: * <p>
0133: * A tabbed panel calls the hover listeners in the following order:
0134: * <ol>
0135: * <li>The hover listener for the tabbed panel itself.
0136: * <li>The hover listener for the tab area or the content area depending on where the
0137: * mouse pointer is located.
0138: * <li>The hover listener for the tab area components area if the mouse pointer is over
0139: * that area.
0140: * </ol>
0141: * When the tabbed panel is no longer hovered, the hover listenrs are called in the
0142: * reverse order.
0143: * </p>
0144: *
0145: * <p>
0146: * It is possible to specify different hover policies ({@link TabbedPanelHoverPolicy})
0147: * in the TabbedPanelProperties that affects all hover areas of the tabbed panel.
0148: * </p>
0149: *
0150: * @author $Author: jesper $
0151: * @version $Revision: 1.167 $
0152: * @see Tab
0153: * @see TitledTab
0154: * @see TabbedPanelProperties
0155: * @see TabListener
0156: * @see TabbedPanelHoverPolicy
0157: * @see HoverListener
0158: */
0159: public class TabbedPanel extends JPanel {
0160: // Shadow property values
0161: private int shadowSize = 4;
0162: private ComponentPaintChecker shadowRepaintChecker;
0163:
0164: private TabDropDownList dropDownList;
0165:
0166: private JComponent contentPanel;
0167:
0168: private JComponent[] tabAreaComponents;
0169:
0170: private Direction tabAreaOrientation;
0171: private TabDropDownListVisiblePolicy listVisiblePolicy = TabDropDownListVisiblePolicy.NEVER;
0172: private TabLayoutPolicy listTabLayoutPolicy = TabLayoutPolicy.SCROLLING;
0173: private DraggableComponentBox draggableComponentBox = new DraggableComponentBox(
0174: TabbedUIDefaults.getButtonIconSize(), false);
0175: private ArrayList listeners;
0176: private TabbedPanelProperties properties = new TabbedPanelProperties(
0177: TabbedPanelProperties.getDefaultProperties());
0178: private Tab highlightedTab;
0179:
0180: private boolean settingHighlighted;
0181: private boolean mouseEntered = false;
0182: private boolean removingSelected = false;
0183:
0184: private TabAreaVisiblePolicy areaVisiblePolicy = TabAreaVisiblePolicy.ALWAYS;
0185:
0186: private class HoverablePanel extends HoverableShapedPanel {
0187: public HoverablePanel(LayoutManager l, HoverListener listener) {
0188: super (l, listener, TabbedPanel.this );
0189: }
0190:
0191: protected void processMouseEvent(MouseEvent event) {
0192: super .processMouseEvent(event);
0193: doProcessMouseEvent(event);
0194: }
0195:
0196: protected void processMouseMotionEvent(MouseEvent event) {
0197: super .processMouseMotionEvent(event);
0198: doProcessMouseMotionEvent(event);
0199: }
0200:
0201: public boolean acceptHover(ArrayList enterableHoverables) {
0202: return getHoverListener() == null ? false
0203: : TabbedHoverUtil.acceptTabbedPanelHover(properties
0204: .getHoverPolicy(), enterableHoverables,
0205: TabbedPanel.this , this );
0206: }
0207: }
0208:
0209: private ShadowPanel componentsPanel = new ShadowPanel();
0210:
0211: private ScrollButtonBox scrollButtonBox;
0212:
0213: private GridBagConstraints constraints = new GridBagConstraints();
0214: private GridBagLayout tabAreaLayoutManager = new GridBagLayout() {
0215: public void layoutContainer(Container parent) {
0216: setTabAreaComponentsButtonsVisible();
0217: super .layoutContainer(parent);
0218:
0219: // Overlap if tab area is too narrow to fit both tabAreaComponentsPanel and draggableComponentBox
0220: if (tabAreaComponentsPanel.isVisible()) {
0221: if (tabAreaOrientation.isHorizontal()) {
0222: if (tabAreaContainer.getHeight() < tabAreaComponentsPanel
0223: .getPreferredSize().getHeight()) {
0224: draggableComponentBox.setSize(
0225: draggableComponentBox.getWidth(), 0);
0226: tabAreaComponentsPanel.setSize(
0227: tabAreaComponentsPanel.getWidth(),
0228: tabAreaContainer.getHeight());
0229: }
0230: } else {
0231: if (tabAreaContainer.getWidth() < tabAreaComponentsPanel
0232: .getPreferredSize().getWidth()) {
0233: draggableComponentBox.setSize(0,
0234: draggableComponentBox.getHeight());
0235: tabAreaComponentsPanel.setSize(tabAreaContainer
0236: .getWidth(), tabAreaComponentsPanel
0237: .getHeight());
0238: }
0239: }
0240: }
0241:
0242: /*if (contentPanel != null) {
0243: int newSize = (tabAreaOrientation == Direction.UP || tabAreaOrientation == Direction.DOWN) ?
0244: draggableComponentBox.getWidth() : draggableComponentBox.getHeight();
0245: int newOuterSize = (tabAreaOrientation == Direction.UP || tabAreaOrientation == Direction.DOWN) ?
0246: tabAreaContainer.getWidth() : tabAreaContainer.getHeight();
0247: if (newOuterSize == outerSize && newSize != size) {
0248: size = newSize;
0249: SwingUtilities.invokeLater(new Runnable() {
0250: public void run() {
0251: if (contentPanel.isShowing()) {
0252: contentPanel.repaint();
0253: }
0254: }
0255: });
0256: }
0257: outerSize = newOuterSize;
0258: }*/
0259:
0260: updateShadow();
0261: }
0262: };
0263:
0264: private HoverableShapedPanel tabAreaContainer = new HoverablePanel(
0265: tabAreaLayoutManager, properties.getTabAreaProperties()
0266: .getHoverListener()) {
0267: public Dimension getPreferredSize() {
0268: Dimension d = super .getPreferredSize();
0269:
0270: if (getTabCount() == 0) {
0271: Insets insets = getInsets();
0272: Dimension d2 = tabAreaComponentsPanel
0273: .getPreferredSize();
0274: d = new Dimension(
0275: insets.left + insets.right + d2.width,
0276: insets.top + insets.bottom + d2.height);
0277: }
0278:
0279: return d;
0280: }
0281: };
0282:
0283: private HoverableShapedPanel tabAreaComponentsPanel = new HoverablePanel(
0284: new DirectionLayout(), properties
0285: .getTabAreaComponentsProperties()
0286: .getHoverListener()) {
0287: public Dimension getMaximumSize() {
0288: return getPreferredSize();
0289: }
0290:
0291: public Dimension getMinimumSize() {
0292: return getPreferredSize();
0293: }
0294:
0295: public Dimension getPreferredSize() {
0296: Dimension d = super .getPreferredSize();
0297: Insets insets = getInsets();
0298:
0299: if (ComponentUtil.hasVisibleChildren(this )) {
0300: if (tabAreaOrientation.isHorizontal()) {
0301: int maxWidth = ComponentUtil
0302: .getPreferredMaxWidth(getComponents())
0303: + insets.left + insets.right;
0304: return new Dimension(maxWidth, d.height);
0305: } else {
0306: int maxHeight = ComponentUtil
0307: .getPreferredMaxHeight(getComponents())
0308: + insets.top + insets.bottom;
0309: return new Dimension(d.width, maxHeight);
0310: }
0311: }
0312:
0313: return new Dimension(0, 0);
0314: }
0315: };
0316:
0317: private DraggableComponentBoxListener draggableComponentBoxListener = new DraggableComponentBoxListener() {
0318: private boolean selectedMoved;
0319:
0320: public void componentSelected(DraggableComponentBoxEvent event) {
0321: if (event.getDraggableComponent() == event
0322: .getOldDraggableComponent()) {
0323: if (!selectedMoved && properties.getTabDeselectable())
0324: draggableComponentBox
0325: .selectDraggableComponent(null);
0326: } else {
0327: Tab tab = findTab(event.getDraggableComponent());
0328: setHighlightedTab(tab);
0329: Tab oldTab = findTab(event.getOldDraggableComponent());
0330: fireSelectedEvent(tab, oldTab);
0331: if (removingSelected) {
0332: removingSelected = false;
0333: if (oldTab != null)
0334: oldTab.setTabbedPanel(null);
0335: }
0336: }
0337:
0338: tabAreaContainer.repaint();
0339: }
0340:
0341: public void componentRemoved(DraggableComponentBoxEvent event) {
0342: Tab tab = findTab(event.getDraggableComponent());
0343: if (highlightedTab == tab)
0344: highlightedTab = null;
0345:
0346: setTabAreaComponentsButtonsVisible();
0347: updateTabAreaVisibility();
0348: //revalidate();
0349: tabAreaContainer.repaint();
0350: fireRemovedEvent(tab);
0351: }
0352:
0353: public void componentAdded(DraggableComponentBoxEvent event) {
0354: updateTabAreaVisibility();
0355: //revalidate();
0356: tabAreaContainer.repaint();
0357: fireAddedEvent(findTab(event.getDraggableComponent()));
0358: }
0359:
0360: public void componentDragged(DraggableComponentBoxEvent event) {
0361: fireDraggedEvent(findTab(event.getDraggableComponent()),
0362: event.getDraggableComponentEvent().getMouseEvent());
0363: }
0364:
0365: public void componentDropped(DraggableComponentBoxEvent event) {
0366: if (!draggableComponentBox.contains(event
0367: .getDraggableComponentBoxPoint()))
0368: setHighlightedTab(findTab(draggableComponentBox
0369: .getSelectedDraggableComponent()));
0370: fireDroppedEvent(findTab(event.getDraggableComponent()),
0371: event.getDraggableComponentEvent().getMouseEvent());
0372: }
0373:
0374: public void componentDragAborted(
0375: DraggableComponentBoxEvent event) {
0376: fireNotDroppedEvent(findTab(event.getDraggableComponent()));
0377: }
0378:
0379: public void changed(DraggableComponentBoxEvent event) {
0380: if (event.getDraggableComponentEvent() != null) {
0381: int type = event.getDraggableComponentEvent().getType();
0382:
0383: if (type == DraggableComponentEvent.TYPE_PRESSED
0384: && properties.getHighlightPressedTab()) {
0385: if (highlightedTab != null)
0386: setHighlightedTab(findTab(event
0387: .getDraggableComponent()));
0388: } else if (type == DraggableComponentEvent.TYPE_RELEASED) {
0389: selectedMoved = false;
0390: setHighlightedTab(getSelectedTab());
0391: } else if (type == DraggableComponentEvent.TYPE_DISABLED
0392: && highlightedTab != null
0393: && highlightedTab.getDraggableComponent() == event
0394: .getDraggableComponent())
0395: setHighlightedTab(null);
0396: else if (type == DraggableComponentEvent.TYPE_ENABLED
0397: && draggableComponentBox
0398: .getSelectedDraggableComponent() == event
0399: .getDraggableComponent())
0400: setHighlightedTab(findTab(event
0401: .getDraggableComponent()));
0402: else if (type == DraggableComponentEvent.TYPE_MOVED) {
0403: tabAreaContainer.repaint();
0404: selectedMoved = event.getDraggableComponent() == draggableComponentBox
0405: .getSelectedDraggableComponent();
0406: fireTabMoved(findTab(event.getDraggableComponent()));
0407: }
0408: } else {
0409: // Scrolling
0410: tabAreaContainer.repaint();
0411: }
0412:
0413: updateShadow();
0414: }
0415: };
0416:
0417: private PropertyMapTreeListener propertyChangedListener = new PropertyMapTreeListener() {
0418: public void propertyValuesChanged(Map changes) {
0419: updateProperties(changes);
0420: updatePropertiesForTabArea(changes);
0421: updatePropertiesForTabAreaComponentsArea(changes);
0422: updatePropertiesForTabAreaComponentsButtons(changes);
0423:
0424: updateScrollButtons();
0425: checkIfOnlyOneTab(true);
0426: }
0427: };
0428:
0429: private void updatePropertiesForTabAreaComponentsButtons(Map changes) {
0430: TabbedPanelButtonProperties buttonProps = properties
0431: .getButtonProperties();
0432: Map m = (Map) changes.get(buttonProps
0433: .getTabDropDownListButtonProperties().getMap());
0434: {
0435: if (m != null) {
0436: if (dropDownList != null) {
0437: AbstractButton b = dropDownList.getButton();
0438: if (m.keySet().contains(ButtonProperties.FACTORY)) {
0439: b = properties.getButtonProperties()
0440: .getTabDropDownListButtonProperties()
0441: .getFactory().createButton(
0442: TabbedPanel.this );
0443: dropDownList.setButton(b);
0444: }
0445:
0446: properties.getButtonProperties()
0447: .getTabDropDownListButtonProperties()
0448: .applyTo(b);
0449: }
0450: }
0451: }
0452:
0453: if (scrollButtonBox != null) {
0454: AbstractButton buttons[] = new AbstractButton[] {
0455: scrollButtonBox.getUpButton(),
0456: scrollButtonBox.getDownButton(),
0457: scrollButtonBox.getLeftButton(),
0458: scrollButtonBox.getRightButton() };
0459:
0460: ButtonProperties props[] = new ButtonProperties[] {
0461: buttonProps.getScrollUpButtonProperties(),
0462: buttonProps.getScrollDownButtonProperties(),
0463: buttonProps.getScrollLeftButtonProperties(),
0464: buttonProps.getScrollRightButtonProperties() };
0465:
0466: for (int i = 0; i < buttons.length; i++) {
0467: m = (Map) changes.get(props[i].getMap());
0468: if (m != null) {
0469: if (m.keySet().contains(ButtonProperties.FACTORY))
0470: buttons[i] = props[i].getFactory()
0471: .createButton(TabbedPanel.this );
0472:
0473: props[i].applyTo(buttons[i]);
0474: }
0475: }
0476:
0477: scrollButtonBox.setButtons(buttons[0], buttons[1],
0478: buttons[2], buttons[3]);
0479: }
0480: }
0481:
0482: private void updateAllDefaultValues() {
0483: // General
0484: updateAllTabsProperties();
0485: draggableComponentBox.setScrollEnabled(properties
0486: .getTabLayoutPolicy() == TabLayoutPolicy.SCROLLING);
0487: updateTabDropDownList();
0488: draggableComponentBox.setScrollOffset(properties
0489: .getTabScrollingOffset());
0490: draggableComponentBox.setEnsureSelectedVisible(properties
0491: .getEnsureSelectedTabVisible());
0492:
0493: tabAreaOrientation = properties.getTabAreaOrientation();
0494: updatePropertiesForTabAreaLayoutConstraints();
0495: componentsPanel.add(tabAreaContainer, ComponentUtil
0496: .getBorderLayoutOrientation(tabAreaOrientation));
0497: componentsPanel.revalidate();
0498:
0499: draggableComponentBox.setComponentSpacing(properties
0500: .getTabSpacing());
0501: draggableComponentBox
0502: .setDepthSortOrder(properties.getTabDepthOrderPolicy() == TabDepthOrderPolicy.DESCENDING);
0503: draggableComponentBox.setAutoSelect(properties
0504: .getAutoSelectTab());
0505:
0506: shadowSize = properties.getShadowSize();
0507: componentsPanel.setBorder(contentPanel != null
0508: && properties.getShadowEnabled() ? new EmptyBorder(0,
0509: 0, shadowSize, shadowSize) : null);
0510:
0511: componentsPanel.setHoverListener(properties.getHoverListener());
0512:
0513: // Tab area
0514: tabAreaContainer.setHoverListener(properties
0515: .getTabAreaProperties().getHoverListener());
0516: ShapedPanelProperties shapedProps = properties
0517: .getTabAreaProperties().getShapedPanelProperties();
0518: properties.getTabAreaProperties().getComponentProperties()
0519: .applyTo(tabAreaContainer);
0520: updateIntelligentInsets(tabAreaContainer, properties
0521: .getTabAreaProperties().getComponentProperties());
0522: updateShapedPanelProperties(tabAreaContainer, properties
0523: .getTabAreaProperties().getShapedPanelProperties());
0524:
0525: // Tab area components area
0526: tabAreaComponentsPanel.setHoverListener(properties
0527: .getTabAreaComponentsProperties().getHoverListener());
0528: updatePropertiesForTabAreaLayoutConstraints();
0529: shapedProps = properties.getTabAreaComponentsProperties()
0530: .getShapedPanelProperties();
0531: properties.getTabAreaComponentsProperties()
0532: .getComponentProperties().applyTo(
0533: tabAreaComponentsPanel);
0534: updateIntelligentInsets(tabAreaComponentsPanel, properties
0535: .getTabAreaComponentsProperties()
0536: .getComponentProperties());
0537: updateShapedPanelProperties(tabAreaComponentsPanel, shapedProps);
0538: tabAreaComponentsPanel
0539: .setHorizontalFlip(tabAreaOrientation == Direction.DOWN
0540: || tabAreaOrientation == Direction.LEFT ? !shapedProps
0541: .getHorizontalFlip()
0542: : shapedProps.getHorizontalFlip());
0543: tabAreaComponentsPanel.setVerticalFlip(shapedProps
0544: .getVerticalFlip());
0545:
0546: updatePanelOpaque();
0547: }
0548:
0549: private void updateProperties(Map changes) {
0550: Map m = getMap(changes, properties.getMap());
0551: if (m != null) {
0552: Set keySet = m.keySet();
0553:
0554: // Properties contained by tabs
0555: if (keySet
0556: .contains(TabbedPanelProperties.TAB_REORDER_ENABLED)
0557: || m.keySet().contains(
0558: TabbedPanelProperties.ABORT_DRAG_KEY)
0559: || m.keySet().contains(
0560: TabbedPanelProperties.TAB_SELECT_TRIGGER))
0561: updateAllTabsProperties();
0562:
0563: // Other
0564: if (keySet
0565: .contains(TabbedPanelProperties.TAB_LAYOUT_POLICY)
0566: && getTabCount() > 1)
0567: draggableComponentBox
0568: .setScrollEnabled(((TabLayoutPolicy) ((ValueChange) m
0569: .get(TabbedPanelProperties.TAB_LAYOUT_POLICY))
0570: .getNewValue()) == TabLayoutPolicy.SCROLLING);
0571:
0572: if (keySet
0573: .contains(TabbedPanelProperties.TAB_DROP_DOWN_LIST_VISIBLE_POLICY))
0574: updateTabDropDownList();
0575:
0576: if (keySet
0577: .contains(TabbedPanelProperties.TAB_SCROLLING_OFFSET))
0578: draggableComponentBox
0579: .setScrollOffset(((Integer) ((ValueChange) m
0580: .get(TabbedPanelProperties.TAB_SCROLLING_OFFSET))
0581: .getNewValue()).intValue());
0582:
0583: if (keySet
0584: .contains(TabbedPanelProperties.ENSURE_SELECTED_VISIBLE))
0585: draggableComponentBox
0586: .setEnsureSelectedVisible(((Boolean) ((ValueChange) m
0587: .get(TabbedPanelProperties.ENSURE_SELECTED_VISIBLE))
0588: .getNewValue()).booleanValue());
0589:
0590: if (keySet
0591: .contains(TabbedPanelProperties.TAB_AREA_ORIENTATION)) {
0592: tabAreaOrientation = (Direction) ((ValueChange) m
0593: .get(TabbedPanelProperties.TAB_AREA_ORIENTATION))
0594: .getNewValue();
0595: updatePropertiesForTabAreaLayoutConstraints();
0596: componentsPanel.remove(tabAreaContainer);
0597: componentsPanel
0598: .add(
0599: tabAreaContainer,
0600: ComponentUtil
0601: .getBorderLayoutOrientation(tabAreaOrientation));
0602:
0603: componentsPanel.revalidate();
0604:
0605: properties.getTabAreaComponentsProperties()
0606: .getComponentProperties().applyTo(
0607: tabAreaComponentsPanel);
0608: updateIntelligentInsets(tabAreaContainer, properties
0609: .getTabAreaProperties()
0610: .getComponentProperties());
0611: tabAreaComponentsPanel.setDirection(tabAreaOrientation
0612: .getNextCW());
0613: updateIntelligentInsets(tabAreaComponentsPanel,
0614: properties.getTabAreaComponentsProperties()
0615: .getComponentProperties());
0616: }
0617:
0618: if (keySet.contains(TabbedPanelProperties.TAB_SPACING))
0619: draggableComponentBox
0620: .setComponentSpacing(((Integer) ((ValueChange) m
0621: .get(TabbedPanelProperties.TAB_SPACING))
0622: .getNewValue()).intValue());
0623:
0624: if (keySet.contains(TabbedPanelProperties.TAB_DEPTH_ORDER))
0625: draggableComponentBox
0626: .setDepthSortOrder(((TabDepthOrderPolicy) ((ValueChange) m
0627: .get(TabbedPanelProperties.TAB_DEPTH_ORDER))
0628: .getNewValue()) == TabDepthOrderPolicy.DESCENDING);
0629:
0630: if (keySet.contains(TabbedPanelProperties.AUTO_SELECT_TAB))
0631: draggableComponentBox
0632: .setAutoSelect(((Boolean) ((ValueChange) m
0633: .get(TabbedPanelProperties.AUTO_SELECT_TAB))
0634: .getNewValue()).booleanValue());
0635:
0636: /*
0637: * if
0638: * (keySet.contains(TabbedPanelProperties.HIGHLIGHT_PRESSED_TAB)) { //
0639: * Elsewhere }
0640: *
0641: * if (keySet.contains(TabbedPanelProperties.TAB_DESELECTABLE)) { //
0642: * Elsewhere }
0643: */
0644:
0645: if (keySet.contains(TabbedPanelProperties.SHADOW_ENABLED)
0646: || m.keySet().contains(
0647: TabbedPanelProperties.SHADOW_STRENGTH)
0648: || m.keySet().contains(
0649: TabbedPanelProperties.SHADOW_COLOR)
0650: || m
0651: .keySet()
0652: .contains(
0653: TabbedPanelProperties.SHADOW_BLEND_AREA_SIZE)
0654: || m.keySet().contains(
0655: TabbedPanelProperties.SHADOW_SIZE)
0656: || m
0657: .keySet()
0658: .contains(
0659: TabbedPanelProperties.PAINT_TAB_AREA_SHADOW)) {
0660: shadowSize = properties.getShadowSize();
0661: componentsPanel
0662: .setBorder(contentPanel != null
0663: && properties.getShadowEnabled() ? new EmptyBorder(
0664: 0, 0, shadowSize, shadowSize)
0665: : null);
0666: }
0667:
0668: if (keySet.contains(TabbedPanelProperties.HOVER_LISTENER)) {
0669: componentsPanel
0670: .setHoverListener((HoverListener) ((ValueChange) m
0671: .get(TabbedPanelProperties.HOVER_LISTENER))
0672: .getNewValue());
0673: }
0674: }
0675:
0676: updatePanelOpaque();
0677: }
0678:
0679: private void updatePropertiesForTabArea(Map changes) {
0680: Map m = getMap(changes, properties.getTabAreaProperties()
0681: .getMap());
0682: if (m != null) {
0683: if (m.keySet().contains(TabAreaProperties.HOVER_LISTENER)) {
0684: tabAreaContainer
0685: .setHoverListener((HoverListener) ((ValueChange) m
0686: .get(TabAreaProperties.HOVER_LISTENER))
0687: .getNewValue());
0688: }
0689:
0690: areaVisiblePolicy = getProperties().getTabAreaProperties()
0691: .getTabAreaVisiblePolicy();
0692: updateTabAreaVisibility();
0693: }
0694:
0695: m = getMap(changes, properties.getTabAreaProperties()
0696: .getComponentProperties().getMap());
0697: Map m2 = getMap(changes, properties.getTabAreaProperties()
0698: .getShapedPanelProperties().getMap());
0699: if (m != null || m2 != null) {
0700: properties.getTabAreaProperties().getComponentProperties()
0701: .applyTo(tabAreaContainer);
0702: updateIntelligentInsets(tabAreaContainer, properties
0703: .getTabAreaProperties().getComponentProperties());
0704:
0705: updateShapedPanelProperties(tabAreaContainer, properties
0706: .getTabAreaProperties().getShapedPanelProperties());
0707:
0708: repaint();
0709: }
0710: }
0711:
0712: private void updateIntelligentInsets(JComponent c,
0713: ComponentProperties props) {
0714: Direction d = properties.getTabAreaOrientation();
0715: Insets insets = props.getInsets();
0716: if (insets != null) {
0717: if (d == Direction.RIGHT)
0718: insets = new Insets(insets.left, insets.bottom,
0719: insets.right, insets.top);
0720: else if (d == Direction.DOWN)
0721: insets = new Insets(insets.bottom, insets.left,
0722: insets.top, insets.right);
0723: else if (d == Direction.LEFT)
0724: insets = new Insets(insets.left, insets.top,
0725: insets.right, insets.bottom);
0726:
0727: Border b = props.getBorder();
0728: c.setBorder(b != null ? (Border) new CompoundBorder(b,
0729: new EmptyBorder(insets))
0730: : (Border) new EmptyBorder(insets));
0731: }
0732: }
0733:
0734: private void updatePropertiesForTabAreaComponentsArea(Map changes) {
0735: Map m = getMap(changes, properties
0736: .getTabAreaComponentsProperties().getMap());
0737:
0738: if (m != null) {
0739: if (m.keySet().contains(
0740: TabAreaComponentsProperties.HOVER_LISTENER)) {
0741: tabAreaComponentsPanel
0742: .setHoverListener((HoverListener) ((ValueChange) m
0743: .get(TabAreaComponentsProperties.HOVER_LISTENER))
0744: .getNewValue());
0745: }
0746:
0747: if (m.keySet().contains(
0748: TabAreaComponentsProperties.STRETCH_ENABLED)) {
0749: updatePropertiesForTabAreaLayoutConstraints();
0750: }
0751: }
0752:
0753: m = getMap(changes, properties.getTabAreaComponentsProperties()
0754: .getComponentProperties().getMap());
0755: Map m2 = getMap(changes, properties
0756: .getTabAreaComponentsProperties()
0757: .getShapedPanelProperties().getMap());
0758: if (m != null || m2 != null) {
0759: ShapedPanelProperties shapedProps = properties
0760: .getTabAreaComponentsProperties()
0761: .getShapedPanelProperties();
0762: properties.getTabAreaComponentsProperties()
0763: .getComponentProperties().applyTo(
0764: tabAreaComponentsPanel);
0765: updateIntelligentInsets(tabAreaComponentsPanel, properties
0766: .getTabAreaComponentsProperties()
0767: .getComponentProperties());
0768: updateShapedPanelProperties(tabAreaComponentsPanel,
0769: shapedProps);
0770: tabAreaComponentsPanel
0771: .setHorizontalFlip(tabAreaOrientation == Direction.DOWN
0772: || tabAreaOrientation == Direction.LEFT ? !shapedProps
0773: .getHorizontalFlip()
0774: : shapedProps.getHorizontalFlip());
0775: tabAreaComponentsPanel.setVerticalFlip(shapedProps
0776: .getVerticalFlip());
0777: }
0778: }
0779:
0780: private void updatePropertiesForTabAreaLayoutConstraints() {
0781: boolean stretch = properties.getTabAreaComponentsProperties()
0782: .getStretchEnabled();
0783: if (tabAreaOrientation == Direction.UP) {
0784: setTabAreaLayoutConstraints(draggableComponentBox, 0, 0,
0785: GridBagConstraints.HORIZONTAL, 1, 1,
0786: GridBagConstraints.SOUTH);
0787: setTabAreaLayoutConstraints(tabAreaComponentsPanel, 1, 0,
0788: stretch ? GridBagConstraints.VERTICAL
0789: : GridBagConstraints.NONE, 0, 1,
0790: GridBagConstraints.SOUTH);
0791: updateTabAreaComponentsPanel(Direction.RIGHT, 0, 1);
0792: } else if (tabAreaOrientation == Direction.DOWN) {
0793: setTabAreaLayoutConstraints(draggableComponentBox, 0, 0,
0794: GridBagConstraints.HORIZONTAL, 1, 1,
0795: GridBagConstraints.NORTH);
0796: setTabAreaLayoutConstraints(tabAreaComponentsPanel, 1, 0,
0797: stretch ? GridBagConstraints.VERTICAL
0798: : GridBagConstraints.NONE, 0, 0,
0799: GridBagConstraints.NORTH);
0800: updateTabAreaComponentsPanel(Direction.RIGHT, 0, 0);
0801: } else if (tabAreaOrientation == Direction.LEFT) {
0802: setTabAreaLayoutConstraints(draggableComponentBox, 0, 0,
0803: GridBagConstraints.VERTICAL, 1, 1,
0804: GridBagConstraints.EAST);
0805: setTabAreaLayoutConstraints(tabAreaComponentsPanel, 0, 1,
0806: stretch ? GridBagConstraints.HORIZONTAL
0807: : GridBagConstraints.NONE, 0, 0,
0808: GridBagConstraints.EAST);
0809: updateTabAreaComponentsPanel(Direction.DOWN, 0, 0);
0810: } else {
0811: setTabAreaLayoutConstraints(draggableComponentBox, 0, 0,
0812: GridBagConstraints.VERTICAL, 1, 1,
0813: GridBagConstraints.WEST);
0814: setTabAreaLayoutConstraints(tabAreaComponentsPanel, 0, 1,
0815: stretch ? GridBagConstraints.HORIZONTAL
0816: : GridBagConstraints.NONE, 0, 0,
0817: GridBagConstraints.WEST);
0818: updateTabAreaComponentsPanel(Direction.DOWN, 0, 1);
0819: }
0820:
0821: draggableComponentBox.setComponentDirection(tabAreaOrientation);
0822: }
0823:
0824: private Map getMap(Map changes, PropertyMap map) {
0825: return changes != null ? (Map) changes.get(map) : null;
0826: }
0827:
0828: private void updateTabAreaVisibility() {
0829: if (areaVisiblePolicy == TabAreaVisiblePolicy.ALWAYS)
0830: tabAreaContainer.setVisible(true);
0831: else if (areaVisiblePolicy == TabAreaVisiblePolicy.NEVER)
0832: tabAreaContainer.setVisible(false);
0833: else if (areaVisiblePolicy == TabAreaVisiblePolicy.MORE_THAN_ONE_TAB)
0834: tabAreaContainer.setVisible(getTabCount() > 1);
0835: else if (areaVisiblePolicy == TabAreaVisiblePolicy.TABS_EXIST)
0836: tabAreaContainer.setVisible(getTabCount() > 0);
0837:
0838: if (!tabAreaContainer.isVisible())
0839: tabAreaContainer.setSize(0, 0);
0840: }
0841:
0842: /**
0843: * Constructs a TabbedPanel with a TabbedPanelContentPanel as content area
0844: * component and with default TabbedPanelProperties
0845: *
0846: * @see TabbedPanelProperties
0847: * @see TabbedPanelContentPanel
0848: */
0849: public TabbedPanel() {
0850: initialize(new TabbedPanelContentPanel(this ,
0851: new TabContentPanel(this )));
0852: }
0853:
0854: /**
0855: * <p>
0856: * Constructs a TabbedPanel with a custom component as content area
0857: * component or without any content area component and with default
0858: * TabbedPanelProperties. The properties for the content area will not be used.
0859: * </p>
0860: *
0861: * <p>
0862: * If no content area component is used, then the tabbed panel will act as a
0863: * bar and the tabs will be laid out in a line.
0864: * </p>
0865: *
0866: * <p>
0867: * <strong>Note: </strong> A custom content area component is by itself
0868: * responsible for showing a tab's content component when a tab is selected,
0869: * for eaxmple by listening to events from the tabbed panel. The component
0870: * will be laid out just as the default content area component so that
0871: * shadows etc. can be used.
0872: * </p>
0873: *
0874: * @param contentAreaComponent component to be used as content area component or null for no
0875: * content area component
0876: * @see TabbedPanelProperties
0877: */
0878: public TabbedPanel(JComponent contentAreaComponent) {
0879: this (contentAreaComponent, false);
0880: }
0881:
0882: /**
0883: * <p>
0884: * Constructs a TabbedPanel with a custom component as content area
0885: * component or without any content area component and with default
0886: * TabbedPanelProperties. It's possible to choose if the properties for the
0887: * content area should be used or not.
0888: * </p>
0889: *
0890: * <p>
0891: * If no content area component is used, then the tabbed panel will act as a
0892: * bar and the tabs will be laid out in a line.
0893: * </p>
0894: *
0895: * <p>
0896: * <strong>Note: </strong> A custom content area component is by itself
0897: * responsible for showing a tab's content component when a tab is selected,
0898: * for eaxmple by listening to events from the tabbed panel. The component
0899: * will be laid out just as the default content area component so that
0900: * shadows etc. can be used.
0901: * </p>
0902: *
0903: * @param contentAreaComponent component to be used as content area component or null for no
0904: * content area component
0905: * @param useProperties true if the properties for the content area should be used,
0906: * otherwise false
0907: * @see TabbedPanelProperties
0908: * @since ITP 1.4.0
0909: */
0910: public TabbedPanel(JComponent contentAreaComponent,
0911: boolean useProperties) {
0912: if (useProperties)
0913: initialize(new TabbedPanelContentPanel(this ,
0914: contentAreaComponent));
0915: else
0916: initialize(contentAreaComponent);
0917: }
0918:
0919: /**
0920: * Check if the tab area contains the given point
0921: *
0922: * @param p the point to check. Must be relative to this tabbed panel.
0923: * @return true if tab area contains point, otherwise false
0924: * @see #contentAreaContainsPoint
0925: */
0926: public boolean tabAreaContainsPoint(Point p) {
0927: if (!tabAreaContainer.isVisible())
0928: return false;
0929:
0930: return tabAreaContainer.contains(SwingUtilities.convertPoint(
0931: this , p, tabAreaContainer));
0932: }
0933:
0934: /**
0935: * Check if the content area contains the given point
0936: *
0937: * @param p the point to check. Must be relative to this tabbed panel.
0938: * @return true if content area contains point, otherwise false
0939: * @see #tabAreaContainsPoint
0940: */
0941: public boolean contentAreaContainsPoint(Point p) {
0942: return contentPanel != null ? contentPanel
0943: .contains(SwingUtilities.convertPoint(this , p,
0944: contentPanel)) : false;
0945: }
0946:
0947: /**
0948: * Checks if the tab area is currently visible
0949: *
0950: * @return true if visible, otherwise false
0951: * @since ITP 1.4.0
0952: */
0953: public boolean isTabAreaVisible() {
0954: return tabAreaContainer.isVisible();
0955: }
0956:
0957: /**
0958: * <p>
0959: * Add a tab. The tab will be added after the last tab.
0960: * </p>
0961: *
0962: * <p>
0963: * If the tab to be added is the only tab in this tabbed panel and the
0964: * property "Auto Select Tab" is enabled then the tab will become selected
0965: * in this tabbed panel after the tab has been added.
0966: * </p>
0967: *
0968: * @param tab tab to be added
0969: * @see #insertTab(Tab, int)
0970: * @see TabbedPanelProperties
0971: */
0972: public void addTab(Tab tab) {
0973: doInsertTab(tab, null, -1);
0974: }
0975:
0976: /**
0977: * <p>
0978: * Insert a tab at the specified tab index (position).
0979: * </p>
0980: *
0981: * <p>
0982: * If the tab to be inserted is the only tab in this tabbed panel and the
0983: * property "Auto Select Tab" is enabled then the tab will become selected
0984: * in this tabbed panel after the tab has been inserted.
0985: * </p>
0986: *
0987: * @param tab tab to be inserted
0988: * @param index the index to insert tab at
0989: * @see #addTab
0990: * @see TabbedPanelProperties
0991: */
0992: public void insertTab(Tab tab, int index) {
0993: doInsertTab(tab, null, index);
0994: }
0995:
0996: /**
0997: * <p>
0998: * Insert a tab at the specified point.
0999: * </p>
1000: *
1001: * <p>
1002: * If the point is outside the tab area then the tab will be inserted after
1003: * the last tab.
1004: * </p>
1005: *
1006: * <p>
1007: * If the tab to be inserted is the only tab in this tabbed panel and the
1008: * property "Auto Select Tab" is enabled then the tab will become selected
1009: * in this tabbed panel after the tab has been inserted.
1010: * </p>
1011: *
1012: * @param tab tab to be inserted
1013: * @param p the point to insert tab at. Must be relative to this tabbed
1014: * panel.
1015: * @see #addTab
1016: * @see TabbedPanelProperties
1017: */
1018: public void insertTab(Tab tab, Point p) {
1019: doInsertTab(tab, p, -1);
1020: }
1021:
1022: /**
1023: * Removes a tab
1024: *
1025: * @param tab tab to be removed from this TabbedPanel
1026: */
1027: public void removeTab(Tab tab) {
1028: if (tab != null && tab.getTabbedPanel() == this ) {
1029: if (getSelectedTab() != tab) {
1030: tab.setTabbedPanel(null);
1031: } else {
1032: removingSelected = true;
1033: }
1034: draggableComponentBox.removeDraggableComponent(tab
1035: .getDraggableComponent());
1036: }
1037: checkIfOnlyOneTab(false);
1038: }
1039:
1040: /**
1041: * Move tab to point p. If p is outside the tab area then the tab is not
1042: * moved.
1043: *
1044: * @param tab tab to move. Tab must be a member (added/inserted) of this
1045: * tabbed panel.
1046: * @param p point to move tab to. Must be relative to this tabbed panel.
1047: */
1048: public void moveTab(Tab tab, Point p) {
1049: draggableComponentBox.dragDraggableComponent(tab
1050: .getDraggableComponent(), SwingUtilities.convertPoint(
1051: this , p, draggableComponentBox));
1052: }
1053:
1054: /**
1055: * Selects a tab, i.e. displays the tab's content component in this tabbed
1056: * panel's content area
1057: *
1058: * @param tab tab to select. Tab must be a member (added/inserted) of this
1059: * tabbed panel.
1060: */
1061: public void setSelectedTab(Tab tab) {
1062: if (getSelectedTab() == tab)
1063: return;
1064:
1065: if (tab != null) {
1066: if (tab.isEnabled() && getTabIndex(tab) > -1) {
1067: if (tab.getDraggableComponent() == draggableComponentBox
1068: .getSelectedDraggableComponent()) {
1069: setHighlightedTab(tab);
1070: } else {
1071: tab.setSelected(true);
1072: }
1073: }
1074: } else {
1075: draggableComponentBox.selectDraggableComponent(null);
1076: }
1077: }
1078:
1079: /**
1080: * Gets the selected tab, i.e. the tab who's content component is currently
1081: * displayed in this tabbed panel's content area
1082: *
1083: * @return the selected tab or null if no tab is selected in this tabbed
1084: * panel
1085: */
1086: public Tab getSelectedTab() {
1087: return findTab(draggableComponentBox
1088: .getSelectedDraggableComponent());
1089: }
1090:
1091: /**
1092: * Sets which tab that should be highlighted, i.e. signal highlighted state
1093: * to the tab
1094: *
1095: * @param highlightedTab tab that should be highlighted or null if no tab should be
1096: * highlighted. The tab must be a member (added/inserted) of this
1097: * tabbed panel.
1098: */
1099: public void setHighlightedTab(Tab highlightedTab) {
1100: if (!settingHighlighted) {
1101: settingHighlighted = true;
1102: Tab oldTab = this .highlightedTab;
1103: Tab newTab = null;
1104: if (oldTab != highlightedTab)
1105: draggableComponentBox
1106: .setTopComponent(highlightedTab != null ? highlightedTab
1107: .getDraggableComponent()
1108: : null);
1109: if (highlightedTab != null) {
1110: if (getTabIndex(highlightedTab) > -1) {
1111: this .highlightedTab = highlightedTab;
1112: if (oldTab != null && oldTab != highlightedTab) {
1113: oldTab.setHighlighted(false);
1114: }
1115:
1116: if (oldTab != highlightedTab)
1117: if (highlightedTab.isEnabled()) {
1118: highlightedTab.setHighlighted(true);
1119: } else {
1120: highlightedTab.setHighlighted(false);
1121: this .highlightedTab = null;
1122: }
1123:
1124: if (highlightedTab.isEnabled()
1125: && highlightedTab != oldTab)
1126: newTab = highlightedTab;
1127:
1128: if (oldTab != highlightedTab)
1129: fireHighlightedEvent(newTab, oldTab);
1130: }
1131: } else if (oldTab != null) {
1132: this .highlightedTab = null;
1133: oldTab.setHighlighted(false);
1134: fireHighlightedEvent(null, oldTab);
1135: }
1136:
1137: updateShadow();
1138: settingHighlighted = false;
1139: }
1140: }
1141:
1142: /**
1143: * Gets the highlighted tab
1144: *
1145: * @return the highlighted tab or null if no tab is highlighted in this
1146: * tabbed panel
1147: */
1148: public Tab getHighlightedTab() {
1149: return highlightedTab;
1150: }
1151:
1152: /**
1153: * Gets the number of tabs
1154: *
1155: * @return number of tabs
1156: */
1157: public int getTabCount() {
1158: return draggableComponentBox.getDraggableComponentCount();
1159: }
1160:
1161: /**
1162: * Gets the tab at index
1163: *
1164: * @param index index of tab
1165: * @return tab at index
1166: * @throws ArrayIndexOutOfBoundsException if there is no tab at index
1167: */
1168: public Tab getTabAt(int index) {
1169: DraggableComponent component = draggableComponentBox
1170: .getDraggableComponentAt(index);
1171: return component == null ? null : (Tab) component
1172: .getComponent();
1173: }
1174:
1175: /**
1176: * Gets the index for tab
1177: *
1178: * @param tab tab
1179: * @return index or -1 if tab is not a member of this TabbedPanel
1180: */
1181: public int getTabIndex(Tab tab) {
1182: return tab == null ? -1
1183: : draggableComponentBox.getDraggableComponentIndex(tab
1184: .getDraggableComponent());
1185: }
1186:
1187: /**
1188: * <p>
1189: * Scrolls the given tab into the visible area of the tab area.
1190: * </p>
1191: *
1192: * <p>
1193: * <strong>Note:</strong> This only has effect if the active tab layout
1194: * policy is scrolling.
1195: * </p>
1196: *
1197: * @param tab tab to scroll into visible tab area
1198: * @since ITP 1.4.0
1199: */
1200: public void scrollTabToVisibleArea(Tab tab) {
1201: if (tab.getTabbedPanel() == this )
1202: draggableComponentBox.scrollToVisible(tab
1203: .getDraggableComponent());
1204: }
1205:
1206: /**
1207: * Sets an array of components that will be shown in the tab area next to
1208: * the tabs, i.e. to the right or below the tabs depending on the tab area
1209: * orientation.
1210: *
1211: * The components will be laid out in a line and the direction
1212: * will change depending on the tab area orientation. Tab drop down list and
1213: * scroll buttons are also tab area components but those are handled
1214: * automatically by the tabbed panel and are not affected by calling this
1215: * method.
1216: *
1217: * @param tabAreaComponents array of components, null for no components
1218: * @since ITP 1.1.0
1219: */
1220: public void setTabAreaComponents(JComponent[] tabAreaComponents) {
1221: if (this .tabAreaComponents != null) {
1222: for (int i = 0; i < this .tabAreaComponents.length; i++)
1223: tabAreaComponentsPanel
1224: .remove(this .tabAreaComponents[i]);
1225: }
1226:
1227: this .tabAreaComponents = tabAreaComponents == null ? null
1228: : (JComponent[]) tabAreaComponents.clone();
1229:
1230: if (tabAreaComponents != null)
1231: for (int i = 0; i < tabAreaComponents.length; i++)
1232: tabAreaComponentsPanel.add(tabAreaComponents[i]);
1233:
1234: setTabAreaComponentsButtonsVisible();
1235: tabAreaComponentsPanel.revalidate();
1236: }
1237:
1238: /**
1239: * Gets if any tab area components i.e. scroll buttons etc are visible at the moment
1240: *
1241: * @return true if visible, otherwise false
1242: * @since ITP 1.2.0
1243: */
1244: public boolean isTabAreaComponentsVisible() {
1245: return tabAreaComponentsPanel.isVisible();
1246: }
1247:
1248: /**
1249: * Gets the tab area components.
1250: *
1251: * Tab drop down list and scroll buttons are also tab area components but
1252: * those are handled automatically by the tabbed panel and no references
1253: * to them will be returned. This method only returns the components that
1254: * have been set with the setTabAreaComponents method.
1255: *
1256: * @return an array of tab area components or null if none
1257: * @see #setTabAreaComponents
1258: * @since ITP 1.1.0
1259: */
1260: public JComponent[] getTabAreaComponents() {
1261: return tabAreaComponents == null ? null
1262: : (JComponent[]) tabAreaComponents.clone();
1263: }
1264:
1265: /**
1266: * Adds a TablListener that will receive events for all the tabs in this
1267: * TabbedPanel
1268: *
1269: * @param listener the TabListener to add
1270: */
1271: public void addTabListener(TabListener listener) {
1272: if (listeners == null)
1273: listeners = new ArrayList(2);
1274:
1275: listeners.add(listener);
1276: }
1277:
1278: /**
1279: * Removes a TabListener
1280: *
1281: * @param listener the TabListener to remove
1282: */
1283: public void removeTabListener(TabListener listener) {
1284: if (listeners != null) {
1285: listeners.remove(listener);
1286:
1287: if (listeners.size() == 0)
1288: listeners = null;
1289: }
1290: }
1291:
1292: /**
1293: * Gets the TabbedPanelProperties
1294: *
1295: * @return the TabbedPanelProperties for this tabbed panel
1296: */
1297: public TabbedPanelProperties getProperties() {
1298: return properties;
1299: }
1300:
1301: /**
1302: * Checks if this tabbed panel has a content area
1303: *
1304: * @return true if content area exist, otherwise false
1305: * @since ITP 1.3.0
1306: */
1307: public boolean hasContentArea() {
1308: return contentPanel != null;
1309: }
1310:
1311: DraggableComponentBox getDraggableComponentBox() {
1312: return draggableComponentBox;
1313: }
1314:
1315: private void initialize(JComponent contentPanel) {
1316: setLayout(new BorderLayout());
1317:
1318: shadowRepaintChecker = new ComponentPaintChecker(this );
1319:
1320: setOpaque(false);
1321:
1322: draggableComponentBox.setOuterParentArea(tabAreaContainer);
1323: tabAreaContainer.add(tabAreaComponentsPanel);
1324: tabAreaContainer.add(draggableComponentBox);
1325:
1326: this .contentPanel = contentPanel;
1327: draggableComponentBox
1328: .addListener(draggableComponentBoxListener);
1329:
1330: if (contentPanel != null) {
1331: componentsPanel.add(contentPanel, BorderLayout.CENTER);
1332: }
1333:
1334: add(componentsPanel, BorderLayout.CENTER);
1335:
1336: updateAllDefaultValues();
1337:
1338: PropertyMapWeakListenerManager.addWeakTreeListener(properties
1339: .getMap(), propertyChangedListener);
1340: //updateProperties(null);
1341: }
1342:
1343: /*private void updateProperties(Map changes) {
1344: //componentsPanel.remove(draggableComponentBox);
1345: tabAreaOrientation = properties.getTabAreaOrientation();
1346: updateTabArea();
1347: updateAllTabsProperties();
1348:
1349: componentsPanel.add(tabAreaContainer, ComponentUtil.getBorderLayoutOrientation(tabAreaOrientation));
1350:
1351: // Shadow
1352: shadowSize = properties.getShadowSize();
1353: componentsPanel.setBorder(
1354: contentPanel != null && properties.getShadowEnabled() ? new EmptyBorder(0, 0, shadowSize, shadowSize) : null);
1355:
1356: checkOnlyOneTab(true);
1357:
1358: updateScrollButtons();
1359: updateTabDropDownList();
1360:
1361: //repaint();
1362: //revalidate();
1363: }*/
1364:
1365: private void updateTabDropDownList() {
1366: TabDropDownListVisiblePolicy newListVisiblePolicy = properties
1367: .getTabDropDownListVisiblePolicy();
1368: TabLayoutPolicy newListTabLayoutPolicy = properties
1369: .getTabLayoutPolicy();
1370:
1371: if (newListVisiblePolicy != listVisiblePolicy
1372: || newListTabLayoutPolicy != listTabLayoutPolicy) {
1373: if (dropDownList != null) {
1374: tabAreaComponentsPanel.remove(dropDownList);
1375: dropDownList.dispose();
1376: dropDownList = null;
1377: }
1378:
1379: if (newListVisiblePolicy == TabDropDownListVisiblePolicy.MORE_THAN_ONE_TAB
1380: || (newListVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE && newListTabLayoutPolicy == TabLayoutPolicy.SCROLLING)) {
1381: dropDownList = new TabDropDownList(
1382: this ,
1383: properties
1384: .getButtonProperties()
1385: .getTabDropDownListButtonProperties()
1386: .applyTo(
1387: properties
1388: .getButtonProperties()
1389: .getTabDropDownListButtonProperties()
1390: .getFactory()
1391: .createButton(this )));
1392: tabAreaComponentsPanel.add(dropDownList,
1393: scrollButtonBox == null ? 0 : 1);
1394:
1395: if (newListVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE)
1396: dropDownList.setVisible(false);
1397: }
1398: }
1399:
1400: listVisiblePolicy = newListVisiblePolicy;
1401: listTabLayoutPolicy = newListTabLayoutPolicy;
1402:
1403: if (dropDownList != null
1404: && !draggableComponentBox.isScrollEnabled()
1405: && listVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE)
1406: dropDownList.setVisible(false);
1407:
1408: tabAreaComponentsPanel.revalidate();
1409: }
1410:
1411: private void updateAllTabsProperties() {
1412: Component[] components = draggableComponentBox
1413: .getBoxComponents();
1414: for (int i = 0; i < components.length; i++)
1415: updateTabProperties((Tab) components[i]);
1416: }
1417:
1418: private void updateTabProperties(Tab tab) {
1419: tab.getDraggableComponent().setAbortDragKeyCode(
1420: properties.getAbortDragKey());
1421: tab.getDraggableComponent().setReorderEnabled(
1422: properties.getTabReorderEnabled());
1423: tab
1424: .getDraggableComponent()
1425: .setSelectOnMousePress(
1426: properties.getTabSelectTrigger() == TabSelectTrigger.MOUSE_PRESS);
1427: }
1428:
1429: private void updateTabAreaComponentsPanel(Direction direction,
1430: int alignmentX, int alignmentY) {
1431: ((DirectionLayout) tabAreaComponentsPanel.getLayout())
1432: .setDirection(direction);
1433: }
1434:
1435: private void updateShapedPanelProperties(ShapedPanel panel,
1436: ShapedPanelProperties shapedPanelProperties) {
1437:
1438: InternalPropertiesUtil.applyTo(shapedPanelProperties, panel,
1439: properties.getTabAreaOrientation().getNextCW());
1440: }
1441:
1442: private void setTabAreaLayoutConstraints(JComponent c, int gridx,
1443: int gridy, int fill, double weightx, double weighty,
1444: int anchor) {
1445: constraints.gridx = gridx;
1446: constraints.gridy = gridy;
1447: constraints.fill = fill;
1448: constraints.weightx = weightx;
1449: constraints.weighty = weighty;
1450: constraints.anchor = anchor;
1451:
1452: tabAreaLayoutManager.setConstraints(c, constraints);
1453: }
1454:
1455: private void doInsertTab(Tab tab, Point p, int index) {
1456: if (tab != null
1457: && !draggableComponentBox
1458: .containsDraggableComponent(tab
1459: .getDraggableComponent())) {
1460: tab.setTabbedPanel(this );
1461: if (p != null)
1462: draggableComponentBox.insertDraggableComponent(tab
1463: .getDraggableComponent(), SwingUtilities
1464: .convertPoint(this , p, draggableComponentBox));
1465: else
1466: draggableComponentBox.insertDraggableComponent(tab
1467: .getDraggableComponent(), index);
1468: updateTabProperties(tab);
1469: checkIfOnlyOneTab(true);
1470: }
1471: }
1472:
1473: private Tab findTab(DraggableComponent draggableComponent) {
1474: return draggableComponent == null ? null
1475: : (Tab) draggableComponent.getComponent();
1476: }
1477:
1478: private void checkIfOnlyOneTab(boolean inc) {
1479: if (getTabCount() == 1) {
1480: draggableComponentBox.setScrollEnabled(false);
1481: updateScrollButtons();
1482: } else if (inc && getTabCount() == 2) {
1483: draggableComponentBox.setScrollEnabled(properties
1484: .getTabLayoutPolicy() == TabLayoutPolicy.SCROLLING);
1485: updateScrollButtons();
1486: updateTabDropDownList();
1487: }
1488: }
1489:
1490: private void setTabAreaComponentsButtonsVisible() {
1491: if (scrollButtonBox != null) {
1492: boolean visible = false;
1493: if (!tabAreaOrientation.isHorizontal())
1494: visible = draggableComponentBox.getInnerSize()
1495: .getWidth() > calcScrollWidth();
1496: else
1497: visible = draggableComponentBox.getInnerSize()
1498: .getHeight() > calcScrollHeight();
1499: scrollButtonBox.setVisible(visible);
1500:
1501: if (dropDownList != null
1502: && listVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE)
1503: dropDownList.setVisible(visible);
1504:
1505: if (!visible) {
1506: scrollButtonBox.setButton1Enabled(false);
1507: scrollButtonBox.setButton2Enabled(true);
1508: }
1509: } else {
1510: if (dropDownList != null
1511: && listVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE)
1512: dropDownList.setVisible(false);
1513: }
1514:
1515: tabAreaComponentsPanel.setVisible(ComponentUtil
1516: .hasVisibleChildren(tabAreaComponentsPanel));
1517: }
1518:
1519: private int calcScrollWidth() {
1520: Insets componentsPanelInsets = tabAreaComponentsPanel
1521: .getInsets();
1522: boolean includeDropDownWidth = dropDownList != null
1523: && listVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE;
1524: boolean componentsVisible = includeDropDownWidth ? ComponentUtil
1525: .isOnlyVisibleComponents(new Component[] {
1526: scrollButtonBox, dropDownList })
1527: : ComponentUtil.isOnlyVisibleComponent(scrollButtonBox);
1528: int insetsWidth = tabAreaComponentsPanel.isVisible()
1529: && componentsVisible ? componentsPanelInsets.left
1530: + componentsPanelInsets.right : 0;
1531: int componentsPanelWidth = tabAreaComponentsPanel.isVisible() ? ((int) tabAreaComponentsPanel
1532: .getPreferredSize().getWidth()
1533: - insetsWidth - (scrollButtonBox.isVisible() ? scrollButtonBox
1534: .getWidth()
1535: + (includeDropDownWidth ? dropDownList.getWidth() : 0)
1536: : 0))
1537: : 0;
1538: Insets areaInsets = tabAreaContainer.getInsets();
1539: return tabAreaContainer.getWidth() - componentsPanelWidth
1540: - areaInsets.left - areaInsets.right;
1541: }
1542:
1543: private int calcScrollHeight() {
1544: Insets componentsPanelInsets = tabAreaComponentsPanel
1545: .getInsets();
1546: boolean includeDropDownHeight = listVisiblePolicy == TabDropDownListVisiblePolicy.TABS_NOT_VISIBLE;
1547: boolean componentsVisible = includeDropDownHeight ? ComponentUtil
1548: .isOnlyVisibleComponents(new Component[] {
1549: scrollButtonBox, dropDownList })
1550: : ComponentUtil.isOnlyVisibleComponent(scrollButtonBox);
1551: int insetsHeight = tabAreaComponentsPanel.isVisible()
1552: && componentsVisible ? componentsPanelInsets.top
1553: + componentsPanelInsets.bottom : 0;
1554: int componentsPanelHeight = tabAreaComponentsPanel.isVisible() ? ((int) tabAreaComponentsPanel
1555: .getPreferredSize().getHeight()
1556: - insetsHeight - (scrollButtonBox.isVisible() ? scrollButtonBox
1557: .getHeight()
1558: + (includeDropDownHeight ? dropDownList.getHeight() : 0)
1559: : 0))
1560: : 0;
1561: Insets areaInsets = tabAreaContainer.getInsets();
1562: return tabAreaContainer.getHeight() - componentsPanelHeight
1563: - areaInsets.top - areaInsets.bottom;
1564: }
1565:
1566: private void updateScrollButtons() {
1567: ScrollButtonBox oldScrollButtonBox = scrollButtonBox;
1568: scrollButtonBox = draggableComponentBox.getScrollButtonBox();
1569: if (oldScrollButtonBox != scrollButtonBox) {
1570: if (oldScrollButtonBox != null) {
1571: tabAreaComponentsPanel.remove(oldScrollButtonBox);
1572: }
1573:
1574: if (scrollButtonBox != null) {
1575: scrollButtonBox
1576: .setButtons(
1577: properties
1578: .getButtonProperties()
1579: .getScrollUpButtonProperties()
1580: .applyTo(
1581: properties
1582: .getButtonProperties()
1583: .getScrollUpButtonProperties()
1584: .getFactory()
1585: .createButton(
1586: this )),
1587: properties
1588: .getButtonProperties()
1589: .getScrollDownButtonProperties()
1590: .applyTo(
1591: properties
1592: .getButtonProperties()
1593: .getScrollDownButtonProperties()
1594: .getFactory()
1595: .createButton(
1596: this )),
1597: properties
1598: .getButtonProperties()
1599: .getScrollLeftButtonProperties()
1600: .applyTo(
1601: properties
1602: .getButtonProperties()
1603: .getScrollLeftButtonProperties()
1604: .getFactory()
1605: .createButton(
1606: this )),
1607: properties
1608: .getButtonProperties()
1609: .getScrollRightButtonProperties()
1610: .applyTo(
1611: properties
1612: .getButtonProperties()
1613: .getScrollRightButtonProperties()
1614: .getFactory()
1615: .createButton(
1616: this )));
1617: scrollButtonBox.setVisible(false);
1618: tabAreaComponentsPanel.add(scrollButtonBox, 0);
1619: }
1620:
1621: tabAreaComponentsPanel.revalidate();
1622: }
1623: }
1624:
1625: private void fireTabMoved(Tab tab) {
1626: if (listeners != null) {
1627: TabEvent event = new TabEvent(this , tab);
1628: Object[] l = listeners.toArray();
1629: for (int i = 0; i < l.length; i++)
1630: ((TabListener) l[i]).tabMoved(event);
1631: }
1632: }
1633:
1634: private void fireDraggedEvent(Tab tab, MouseEvent mouseEvent) {
1635: if (listeners != null) {
1636: TabDragEvent event = new TabDragEvent(this , EventUtil
1637: .convert(mouseEvent, tab));
1638: Object[] l = listeners.toArray();
1639: for (int i = 0; i < l.length; i++)
1640: ((TabListener) l[i]).tabDragged(event);
1641: }
1642: }
1643:
1644: private void fireDroppedEvent(Tab tab, MouseEvent mouseEvent) {
1645: if (listeners != null) {
1646: TabDragEvent event = new TabDragEvent(this , EventUtil
1647: .convert(mouseEvent, tab));
1648: Object[] l = listeners.toArray();
1649: for (int i = 0; i < l.length; i++)
1650: ((TabListener) l[i]).tabDropped(event);
1651: }
1652: }
1653:
1654: private void fireNotDroppedEvent(Tab tab) {
1655: if (listeners != null) {
1656: TabEvent event = new TabEvent(this , tab);
1657: Object[] l = listeners.toArray();
1658: for (int i = 0; i < l.length; i++)
1659: ((TabListener) l[i]).tabDragAborted(event);
1660: }
1661: }
1662:
1663: private void fireSelectedEvent(Tab tab, Tab oldTab) {
1664: if (listeners != null) {
1665: {
1666: TabStateChangedEvent event = new TabStateChangedEvent(
1667: this , this , oldTab, oldTab, tab);
1668: Object[] l = listeners.toArray();
1669: for (int i = 0; i < l.length; i++)
1670: ((TabListener) l[i]).tabDeselected(event);
1671: }
1672: {
1673: TabStateChangedEvent event = new TabStateChangedEvent(
1674: this , this , tab, oldTab, tab);
1675: Object[] l = listeners.toArray();
1676: for (int i = 0; i < l.length; i++)
1677: ((TabListener) l[i]).tabSelected(event);
1678: }
1679: }
1680: }
1681:
1682: private void fireHighlightedEvent(Tab tab, Tab oldTab) {
1683: if (listeners != null) {
1684: {
1685: TabStateChangedEvent event = new TabStateChangedEvent(
1686: this , this , oldTab, oldTab, tab);
1687: Object[] l = listeners.toArray();
1688: for (int i = 0; i < l.length; i++)
1689: ((TabListener) l[i]).tabDehighlighted(event);
1690: }
1691: {
1692: TabStateChangedEvent event = new TabStateChangedEvent(
1693: this , this , tab, oldTab, tab);
1694: Object[] l = listeners.toArray();
1695: for (int i = 0; i < l.length; i++)
1696: ((TabListener) l[i]).tabHighlighted(event);
1697: }
1698: }
1699: }
1700:
1701: private void fireAddedEvent(Tab tab) {
1702: if (listeners != null) {
1703: TabEvent event = new TabEvent(this , tab);
1704: Object[] l = listeners.toArray();
1705: for (int i = 0; i < l.length; i++)
1706: ((TabListener) l[i]).tabAdded(event);
1707: }
1708: }
1709:
1710: private void fireRemovedEvent(Tab tab) {
1711: if (listeners != null) {
1712: TabRemovedEvent event = new TabRemovedEvent(this , tab, this );
1713: Object[] l = listeners.toArray();
1714: for (int i = 0; i < l.length; i++)
1715: ((TabListener) l[i]).tabRemoved(event);
1716: }
1717: }
1718:
1719: protected void processMouseEvent(MouseEvent event) {
1720: if (event.getID() == MouseEvent.MOUSE_ENTERED) {
1721: if (!mouseEntered) {
1722: mouseEntered = true;
1723: super .processMouseEvent(event);
1724: }
1725: } else if (event.getID() == MouseEvent.MOUSE_EXITED) {
1726: if (!contains(event.getPoint())) {
1727: mouseEntered = false;
1728: super .processMouseEvent(event);
1729: }
1730: } else
1731: super .processMouseEvent(event);
1732: }
1733:
1734: void doProcessMouseEvent(MouseEvent event) {
1735: processMouseEvent(SwingUtilities.convertMouseEvent(
1736: (Component) event.getSource(), event, this ));
1737: }
1738:
1739: void doProcessMouseMotionEvent(MouseEvent event) {
1740: processMouseMotionEvent(SwingUtilities.convertMouseEvent(
1741: (Component) event.getSource(), event, this ));
1742: }
1743:
1744: private void updateShadow() {
1745: if (shadowRepaintChecker.isPaintingOk() && contentPanel != null
1746: && properties.getShadowEnabled()) {
1747: Point p = SwingUtilities.convertPoint(tabAreaContainer,
1748: new Point(0, 0), this );
1749: repaint(p.x, p.y, tabAreaContainer.getWidth() + shadowSize,
1750: tabAreaContainer.getHeight() + shadowSize);
1751: }
1752: }
1753:
1754: private void updatePanelOpaque() {
1755: if (!properties.getShadowEnabled()
1756: && properties.getTabAreaProperties()
1757: .getShapedPanelProperties().getOpaque()
1758: && (contentPanel == null ? true : properties
1759: .getContentPanelProperties()
1760: .getShapedPanelProperties().getOpaque())) {
1761: BaseContainerUtil.setForcedOpaque(componentsPanel, true);
1762: setOpaque(true);
1763: } else {
1764: BaseContainerUtil.setForcedOpaque(componentsPanel, false);
1765: setOpaque(false);
1766: }
1767: }
1768:
1769: private class ShadowPanel extends HoverablePanel {
1770: ShadowPanel() {
1771: super (new BorderLayout(), properties.getHoverListener());
1772: setCursor(null);
1773: }
1774:
1775: public boolean contains(int x, int y) {
1776: return properties.getShadowEnabled() ? doContains(x, y)
1777: : super .contains(x, y);
1778: }
1779:
1780: public boolean inside(int x, int y) {
1781: return properties.getShadowEnabled() ? doContains(x, y)
1782: : super .inside(x, y);
1783: }
1784:
1785: private boolean doContains(int x, int y) {
1786: Dimension d = DimensionUtil.getInnerDimension(getSize(),
1787: getInsets());
1788: return x >= 0 && y >= 0 && x < d.getWidth()
1789: && y < d.getHeight();
1790: }
1791:
1792: public void paint(Graphics g) {
1793: super .paint(g);
1794:
1795: if (contentPanel == null || !properties.getShadowEnabled())
1796: return;
1797:
1798: new ShadowPainter(
1799: this ,
1800: componentsPanel,
1801: highlightedTab,
1802: contentPanel,
1803: tabAreaComponentsPanel,
1804: tabAreaContainer,
1805: draggableComponentBox,
1806: properties.getTabAreaOrientation(),
1807: properties.getPaintTabAreaShadow(),
1808: shadowSize,
1809: properties.getShadowBlendAreaSize(),
1810: properties.getShadowColor(),
1811: properties.getShadowStrength(),
1812: getTabIndex(getHighlightedTab()) == getTabCount() - 1)
1813: .paint(g);
1814: }
1815: }
1816: }
|