0001: /*
0002: * @(#)JideTabbedPane.java Oct 7, 2002
0003: *
0004: * Copyright 2002 JIDE Software Inc. All rights reserved.
0005: */
0006: package com.jidesoft.swing;
0007:
0008: import com.jidesoft.plaf.JideTabbedPaneUI;
0009: import com.jidesoft.plaf.LookAndFeelFactory;
0010: import com.jidesoft.plaf.UIDefaultsLookup;
0011: import com.jidesoft.plaf.basic.BasicJideTabbedPaneUI;
0012: import com.jidesoft.utils.JideFocusTracker;
0013: import com.jidesoft.utils.SystemInfo;
0014:
0015: import javax.swing.*;
0016: import javax.swing.plaf.TabbedPaneUI;
0017: import javax.swing.plaf.UIResource;
0018: import java.awt.*;
0019: import java.awt.event.FocusAdapter;
0020: import java.awt.event.FocusEvent;
0021: import java.awt.event.FocusListener;
0022: import java.beans.PropertyChangeEvent;
0023: import java.beans.PropertyChangeListener;
0024: import java.util.Hashtable;
0025: import java.util.Map;
0026: import java.util.logging.Level;
0027: import java.util.logging.Logger;
0028:
0029: /**
0030: * <code>JidetabbedPane</code> is an enhanced version of <code>JTabbedPane</code>.
0031: * Different from <code>JTabbedPane</code>, it
0032: * <ul>
0033: * <li> has an option to hide tab area if there is only one
0034: * component in tabbed pane.
0035: * <li> has an option to resize tab width so that all tabs
0036: * can be fitted in one row.
0037: * <li> has an option to show a close button along with scroll left
0038: * and scroll right buttons in tab area.
0039: * </ul>
0040: * Except methods to set additional options specified above, the uage of
0041: * <code>JideTabbedPane</code> is the same as <code>JTabbedPane</code>.
0042: */
0043: public class JideTabbedPane extends JTabbedPane {
0044:
0045: private boolean _hideOneTab = false;
0046:
0047: private boolean _showTabButtons = false;
0048:
0049: private boolean _showCloseButton = false;
0050: private boolean _showCloseButtonOnTab = false;
0051: private boolean _useDefaultShowCloseButtonOnTab = false;
0052: private boolean _showTabArea = true;
0053: private boolean _showTabContent = true;
0054:
0055: private boolean _showIconsOnTab = true;
0056: private boolean _useDefaultShowIconsOnTab = true;
0057:
0058: private boolean _rightClickSelect;
0059: private boolean _dragOverDisabled;
0060:
0061: /**
0062: * Bound property name for shrink tabs.
0063: */
0064: public final static String SHRINK_TAB_PROPERTY = "shrinkTab";
0065:
0066: /**
0067: * Bound property name for hide tab area if there is only one tab.
0068: */
0069: public final static String HIDE_IF_ONE_TAB_PROPERTY = "hideIfOneTab";
0070:
0071: /**
0072: * Bound property name for show tab button.
0073: */
0074: public final static String SHOW_TAB_BUTTONS_PROPERTY = "showTabButtons";
0075:
0076: /**
0077: * Bound property name for box style
0078: */
0079: public final static String BOX_STYLE_PROPERTY = "boxStyle";
0080:
0081: /**
0082: * Bound property name for show icons on tab
0083: */
0084: public final static String SHOW_ICONS_PROPERTY = "showIconsOnTab";
0085:
0086: /**
0087: * Bound property name for using default show icons on tab value from UIDefaults
0088: */
0089: public final static String USE_DEFAULT_SHOW_ICONS_PROPERTY = "useDefaultShowIconsOnTab";
0090:
0091: /**
0092: * Bound property name for if showing close button on tab
0093: */
0094: public final static String SHOW_CLOSE_BUTTON_ON_TAB_PROPERTY = "showCloseButtonOnTab";
0095:
0096: /**
0097: * Bound property name for if showing close button
0098: */
0099: public final static String SHOW_CLOSE_BUTTON_PROPERTY = "showCloseButton";
0100:
0101: /**
0102: * Bound property name for if the tab area is visible.
0103: */
0104: public final static String SHOW_TAB_AREA_PROPERTY = "showTabArea";
0105:
0106: /**
0107: * Bound property name for if the tab area is visible.
0108: */
0109: public final static String SHOW_TAB_CONTENT_PROPERTY = "showTabContent";
0110:
0111: /**
0112: * Bound property name for tab closable.
0113: */
0114: public final static String TAB_CLOSABLE_PROPERTY = "tabClosable";
0115:
0116: /**
0117: * Bound property name for using default show close button on tab value from UIDefaults
0118: */
0119: public final static String USE_DEFAULT_SHOW_CLOSE_BUTTON_ON_TAB_PROPERTY = "useDefaultShowCloseButtonOnTab";
0120:
0121: /**
0122: * Bound property name for if the active tab title is in bold
0123: */
0124: public final static String BOLDACTIVETAB_PROPERTY = "boldActiveTab";
0125:
0126: /**
0127: * Bound property name for gripper.
0128: */
0129: public final static String GRIPPER_PROPERTY = "gripper";
0130:
0131: public final static String PROPERTY_TAB_SHAPE = "tabShape";
0132: public final static String PROPERTY_COLOR_THEME = "colorTheme";
0133: public final static String PROPERTY_TAB_RESIZE_MODE = "tabResizeMode";
0134: public final static String PROPERTY_TAB_LEADING_COMPONENT = "tabLeadingComponent";
0135: public final static String PROPERTY_TAB_TRAILING_COMPONENT = "tabTrailingComponent";
0136: public final static String PROPERTY_TAB_COLOR_PROVIDER = "tabColorProvider";
0137: public final static String PROPERTY_CONTENT_BORDER_INSETS = "contentBorderInsets";
0138: public final static String PROPERTY_DRAG_OVER_DISABLED = "dragOverDisabled";
0139:
0140: /**
0141: * @see #getUIClassID
0142: * @see #readObject
0143: */
0144: private static final String uiClassID = "JideTabbedPaneUI";
0145:
0146: /**
0147: * If the gripper should be shown. Gripper is something on divider to indicate it can be dragged.
0148: */
0149: private boolean _showGripper = false;
0150:
0151: /**
0152: * A converter to shorten
0153: */
0154: private StringConverter _stringConverter;
0155:
0156: private boolean _boldActiveTab = false;
0157:
0158: private Map _closableMap = new Hashtable();
0159:
0160: private Hashtable _pageLastFocusTrackers = new Hashtable();
0161:
0162: private Font _selectedTabFont;
0163:
0164: /**
0165: * A tab resize mode. The default resize mode means it will use the resize mode of {@link #getDefaultTabResizeMode()} which is defined
0166: * in UIDefault "JideTabbedPane.defaultResizeMode". You can change this in UIDefault. It will affect the resize mode of all <code>JideTabbedPane</code>s.
0167: */
0168: public final static int RESIZE_MODE_DEFAULT = 0;
0169:
0170: /**
0171: * A tab resize mode. The none resize mode means the tab will not resize when tabbed pane width changes.
0172: */
0173: public final static int RESIZE_MODE_NONE = 1;
0174:
0175: /**
0176: * A tab resize mode. The fit resize mode means the tabs will shrink if the tabbed pane width shinks so there is no way to display the full contents of the tabs.
0177: */
0178: public final static int RESIZE_MODE_FIT = 2;
0179:
0180: /**
0181: * A tab resize mode. All tabs will be at a fixed width. The fixed width is defined as UIDefault "JideTabbedPane.fixedStyleRectSize" which is an integer.
0182: */
0183: public final static int RESIZE_MODE_FIXED = 3;
0184:
0185: /**
0186: * A tab resize mode. In this mode, the select tab will have full tab width. Non-selected tab will only display the icon. The actual width of non-selected tab is determined by
0187: * UIDefault "JideTabbedPane.compressedStyleNoIconRectSize" which is an integer.
0188: */
0189: public final static int RESIZE_MODE_COMPRESSED = 4;
0190:
0191: private int _tabResizeMode = RESIZE_MODE_DEFAULT;
0192:
0193: /**
0194: * color style
0195: */
0196: public final static int COLOR_THEME_DEFAULT = 0;
0197: public final static int COLOR_THEME_WIN2K = 1;
0198: public final static int COLOR_THEME_OFFICE2003 = 2;
0199: public final static int COLOR_THEME_VSNET = 3;
0200: public final static int COLOR_THEME_WINXP = 4;
0201:
0202: // color style
0203: private int _colorTheme = COLOR_THEME_DEFAULT;
0204:
0205: // tab shape
0206: public final static int SHAPE_DEFAULT = 0;
0207: public final static int SHAPE_WINDOWS = 1;
0208: public final static int SHAPE_VSNET = 2;
0209: public final static int SHAPE_BOX = 3;
0210: public final static int SHAPE_OFFICE2003 = 4;
0211: public final static int SHAPE_FLAT = 5;
0212: public final static int SHAPE_ECLIPSE = 6;
0213: public final static int SHAPE_ECLIPSE3X = 7;
0214: public final static int SHAPE_EXCEL = 8;
0215: public final static int SHAPE_ROUNDED_VSNET = 9;
0216: public final static int SHAPE_ROUNDED_FLAT = 10;
0217: public final static int SHAPE_WINDOWS_SELECTED = 11;
0218:
0219: private int _tabShape = SHAPE_DEFAULT;
0220:
0221: private Component _tabLeadingComponent = null;
0222: private Component _tabTrailingComponent = null;
0223:
0224: // show close button on active tab only
0225: private boolean _showCloseButtonOnSelectedTab = false;
0226:
0227: private ListCellRenderer _tabListCellRenderer;
0228:
0229: private Insets _contentBorderInsets;
0230:
0231: private static final Logger LOGGER_EVENT = Logger
0232: .getLogger(TabEditingEvent.class.getName());
0233:
0234: /**
0235: * Creates an empty <code>TabbedPane</code> with a default
0236: * tab placement of <code>JTabbedPane.TOP</code>.
0237: *
0238: * @see #addTab
0239: */
0240: public JideTabbedPane() {
0241: this (JideTabbedPane.TOP, JideTabbedPane.SCROLL_TAB_LAYOUT);
0242: }
0243:
0244: /**
0245: * Creates an empty <code>TabbedPane</code> with the specified tab placement
0246: * of either: <code>JTabbedPane.TOP</code>, <code>JTabbedPane.BOTTOM</code>,
0247: * <code>JTabbedPane.LEFT</code>, or <code>JTabbedPane.RIGHT</code>.
0248: *
0249: * @param tabPlacement the placement for the tabs relative to the content
0250: * @see #addTab
0251: */
0252: public JideTabbedPane(int tabPlacement) {
0253: this (tabPlacement, JideTabbedPane.SCROLL_TAB_LAYOUT);
0254: }
0255:
0256: /**
0257: * Creates an empty <code>JideTabbedPane</code> with the specified tab placement
0258: * and tab layout policy. Tab placement may be either:
0259: * <code>JTabbedPane.TOP</code> or <code>JTabbedPane.BOTTOM</code>
0260: * Tab layout policy should always be <code>JTabbedPane.SCROLL_TAB_LAYOUT</code>.
0261: * <code>JTabbedPane</code> also supports <code>JTabbedPane.WRAP_TAB_LAYOUT</code>. However the style of
0262: * tabs in <code>JideTabbedPane</code> doesn't match with <code>JTabbedPane.WRAP_TAB_LAYOUT</code>
0263: * very well, so we decided not to support it.
0264: *
0265: * @param tabPlacement the placement for the tabs relative to the content
0266: * @param tabLayoutPolicy the policy for laying out tabs when all tabs will not fit on one run
0267: * @throws IllegalArgumentException if tab placement or tab layout policy are not
0268: * one of the above supported values
0269: * @see #addTab
0270: */
0271: public JideTabbedPane(int tabPlacement, int tabLayoutPolicy) {
0272: super (tabPlacement, tabLayoutPolicy);
0273: // if(tabLayoutPolicy == WRAP_TAB_LAYOUT)
0274: // tabLayoutPolicy = SCROLL_TAB_LAYOUT;
0275:
0276: setModel(new IgnoreableSingleSelectionModel());
0277: }
0278:
0279: /**
0280: * Returns the UI object which implements the L&F for this component.
0281: *
0282: * @return a <code>TabbedPaneUI</code> object
0283: * @see #setUI
0284: */
0285: @Override
0286: public TabbedPaneUI getUI() {
0287: return (TabbedPaneUI) ui;
0288: }
0289:
0290: /**
0291: * Sets the UI object which implements the L&F for this component.
0292: *
0293: * @param ui the new UI object
0294: * @see UIDefaults#getUI
0295: */
0296: @Override
0297: public void setUI(TabbedPaneUI ui) {
0298: super .setUI(ui);
0299: }
0300:
0301: /**
0302: * Resets the UI property to a value from the current look and feel.
0303: *
0304: * @see JComponent#updateUI
0305: */
0306: @Override
0307: public void updateUI() {
0308: if (UIDefaultsLookup.get(uiClassID) == null) {
0309: LookAndFeelFactory.installJideExtension();
0310: }
0311: setUI((TabbedPaneUI) UIManager.getUI(this ));
0312: }
0313:
0314: /**
0315: * Returns the name of the UI class that implements the
0316: * L&F for this component.
0317: *
0318: * @return the string "TabbedPaneUI"
0319: * @see JComponent#getUIClassID
0320: * @see UIDefaults#getUI
0321: */
0322: @Override
0323: public String getUIClassID() {
0324: return uiClassID;
0325: }
0326:
0327: /**
0328: * Returns if tabs are shrinked when avaliable space is not enough to hold all tabs.
0329: *
0330: * @return true if tab shrink is true; false otherwise
0331: * @deprecated Since we added more tab resize option, shrinkTabs is just one of those.
0332: * You can call {@link #getTabResizeMode()}. If the value is {@link #RESIZE_MODE_FIT}, it means
0333: * shrinkTabs is true. Otherwise, it's false.
0334: */
0335: public boolean isShrinkTabs() {
0336: return getTabResizeMode() == RESIZE_MODE_FIT;
0337: }
0338:
0339: /**
0340: * Sets the value if if tabs are shrinked when avaliable space is not enough to hold all tabs.
0341: * PropertyChangeEvent of SHRINK_TAB_PROPERTY will be fired.
0342: *
0343: * @param shrinkTab true to shrink tabs; false otherwise.
0344: * @deprecated Since we added more tab resize option, shrinkTabs is just one of those.
0345: * You can call {@link #setTabResizeMode(int)} and set to {@link #RESIZE_MODE_FIT} which is equavilent
0346: * to setShrinkTabs(true). {@link #RESIZE_MODE_NONE} is equavilent to setShrinkTabs(false).
0347: */
0348: public void setShrinkTabs(boolean shrinkTab) {
0349: boolean oldValue = isShrinkTabs();
0350:
0351: if (oldValue != shrinkTab) {
0352: if (shrinkTab) {
0353: setTabResizeMode(shrinkTab ? RESIZE_MODE_FIT
0354: : RESIZE_MODE_NONE);
0355: }
0356: firePropertyChange(SHRINK_TAB_PROPERTY, oldValue,
0357: isShrinkTabs());
0358: }
0359: }
0360:
0361: /**
0362: * Checks if tab area will be hidden if there is only one tab.
0363: * <br>
0364: * If the showTabButtons option is true, isHideOneTab will
0365: * always return false so that there
0366: * is a place to place those tab buttons.
0367: *
0368: * @return true if tab areas will be hidden if there is only one tab; false otherwise.
0369: */
0370: public boolean isHideOneTab() {
0371: return !isShowTabButtons() && _hideOneTab;
0372: }
0373:
0374: /**
0375: * Sets the value if tab area will be hidden if there is only one tab.
0376: * PropertyChangeEvent of HIDE_IF_ONE_TAB_PROPERTY will be fired.
0377: * <br>
0378: * If the showTabButtons option is true, no matter what option you pass to setHideOneTab,
0379: * isHideOneTab will always return false.
0380: *
0381: * @param hideOne true to hide tab areas if there is only one tab; false otherwise.
0382: */
0383: public void setHideOneTab(boolean hideOne) {
0384: boolean oldValue = _hideOneTab;
0385:
0386: if (oldValue != hideOne) {
0387: _hideOneTab = hideOne;
0388: firePropertyChange(HIDE_IF_ONE_TAB_PROPERTY, oldValue,
0389: _hideOneTab);
0390: }
0391: }
0392:
0393: /**
0394: * Checks if tab area is shown.
0395: *
0396: * @return true if tab area is visible; false otherwise.
0397: */
0398: public boolean isTabShown() {
0399: return isShowTabArea()
0400: && !(isHideOneTab() && getTabCount() <= 1);
0401: }
0402:
0403: /**
0404: * Checks if tab buttons are always visible. Tab buttons are scroll left button,
0405: * scroll right button and close button which appear to the right of tabs in tab area.
0406: * <br>
0407: * If the showTabButtons is set to true, isHideOneTab will
0408: * always return false so that there is a place to place those tab buttons.
0409: *
0410: * @return true if tab buttons are always visible; false otherwise.
0411: */
0412: public boolean isShowTabButtons() {
0413: return _showTabButtons;
0414: }
0415:
0416: /**
0417: * Sets the value if tab buttons are always visible.
0418: * PropertyChangeEvent of SHOW_TAB_BUTTONS_PROPERTY will be fired.
0419: *
0420: * @param showButtons true to always show tab buttons; false otherwise.
0421: */
0422: public void setShowTabButtons(boolean showButtons) {
0423: boolean oldValue = _showTabButtons;
0424:
0425: if (oldValue != showButtons) {
0426: _showTabButtons = showButtons;
0427: firePropertyChange(SHOW_TAB_BUTTONS_PROPERTY, oldValue,
0428: _showTabButtons);
0429: }
0430: }
0431:
0432: /**
0433: * Checks if tabs are displayed as box style.
0434: *
0435: * @return true if tab is box style; false otherwise
0436: * @deprecated As JideTabbedPane can now support many different style, box style is just one of them.
0437: * So this is method is replaced by {@link #getTabShape()} method. If the return value is STYLE_BOX,
0438: * it is a box style tab.
0439: */
0440: public boolean isBoxStyleTab() {
0441: return getTabShape() == SHAPE_BOX;
0442: }
0443:
0444: /**
0445: * Sets the value if tabs are box style.
0446: * PropertyChangeEvent of BOX_STYLE_PROPERTY will be fired.
0447: *
0448: * @param boxStyleTab true to show tab as box style; false otherwise.
0449: * @deprecated As JideTabbedPane can now support many different style, box style is just one of them.
0450: * So a better way is to change style using {@link #setTabShape(int)} method.
0451: */
0452: public void setBoxStyleTab(boolean boxStyleTab) {
0453: boolean oldValue = isBoxStyleTab();
0454:
0455: if (oldValue != boxStyleTab) {
0456: setTabShape(SHAPE_BOX);
0457: firePropertyChange(BOX_STYLE_PROPERTY, oldValue,
0458: isBoxStyleTab());
0459: }
0460: }
0461:
0462: private Action _closeAction;
0463:
0464: /**
0465: * Sets default close action for close button.
0466: *
0467: * @param action the close action.
0468: */
0469: public void setCloseAction(Action action) {
0470: Action old = _closeAction;
0471: if (old != action) {
0472: _closeAction = action;
0473: firePropertyChange("closeTabAction", old, _closeAction);
0474: }
0475: }
0476:
0477: /**
0478: * Gets close action.
0479: *
0480: * @return close action
0481: */
0482: public Action getCloseAction() {
0483: return _closeAction;
0484: }
0485:
0486: /**
0487: * Resets close action to default. Default action
0488: * is to remove currently selected tab.
0489: */
0490: public void resetDefaultCloseAction() {
0491: setCloseAction(null);
0492: }
0493:
0494: private boolean _suppressStateChangedEvents = false;
0495:
0496: @Override
0497: protected void fireStateChanged() {
0498: if (!_suppressStateChangedEvents) {
0499: super .fireStateChanged();
0500: }
0501: }
0502:
0503: // setSelectedIndex will be called during moving tab. So we use this flag to suppress it.
0504: private boolean _suppressSetSelectedIndex = false;
0505:
0506: @Override
0507: public void setSelectedIndex(int index) {
0508: if (!_suppressSetSelectedIndex) {
0509: super .setSelectedIndex(index);
0510: }
0511: }
0512:
0513: private boolean _autoRequestFocus = true;
0514:
0515: /**
0516: * Checks if the UI should automatically request focus on selecte dcomponent when doing the layout.
0517: * This method is only used internally when the tab is being moved.
0518: *
0519: * @return true or false. Default is true.
0520: */
0521: public boolean isAutoRequestFocus() {
0522: return _autoRequestFocus;
0523: }
0524:
0525: private void setAutoRequestFocus(boolean autoRequestFocus) {
0526: _autoRequestFocus = autoRequestFocus;
0527: }
0528:
0529: /**
0530: * Moves selected tab from current position to the position specified in tabIndex.
0531: *
0532: * @param tabIndex new index
0533: */
0534: public void moveSelectedTabTo(int tabIndex) {
0535: int selectedIndex = getSelectedIndex();
0536: if (selectedIndex == tabIndex) { // do nothing
0537: return;
0538: }
0539:
0540: Component selectedComponent = getComponentAt(selectedIndex);
0541:
0542: boolean old = isAutoRequestFocus();
0543:
0544: boolean shouldChangeFocus = false;
0545: // we will not let UI to auto request focus so we will have to do it here.
0546: // if the selected component has focus, we will request it after the tab is moved.
0547: if (selectedComponent != null) {
0548: if (JideSwingUtilities
0549: .isAncestorOfFocusOwner(selectedComponent)) {
0550: shouldChangeFocus = true;
0551: }
0552: }
0553:
0554: try {
0555: _suppressStateChangedEvents = true;
0556: setAutoRequestFocus(false);
0557:
0558: if (selectedIndex - tabIndex == 1
0559: || tabIndex - selectedIndex == 1) {
0560: Component frame = getComponentAt(tabIndex);
0561: String title = getTitleAt(tabIndex);
0562: String tooltip = getToolTipTextAt(tabIndex);
0563: Icon icon = getIconAt(tabIndex);
0564: _suppressSetSelectedIndex = true;
0565: try {
0566: if (tabIndex > selectedIndex)
0567: insertTab(title, icon, frame, tooltip,
0568: selectedIndex);
0569: else {
0570: insertTab(title, icon, frame, tooltip,
0571: selectedIndex + 1);
0572: }
0573: } finally {
0574: _suppressSetSelectedIndex = false;
0575: }
0576: } else {
0577: Component frame = getComponentAt(selectedIndex);
0578: String title = getTitleAt(selectedIndex);
0579: String tooltip = getToolTipTextAt(selectedIndex);
0580: Icon icon = getIconAt(selectedIndex);
0581: _suppressSetSelectedIndex = true;
0582: try {
0583: if (tabIndex > selectedIndex)
0584: insertTab(title, icon, frame, tooltip,
0585: tabIndex + 1);
0586: else {
0587: insertTab(title, icon, frame, tooltip, tabIndex);
0588: }
0589: } finally {
0590: _suppressSetSelectedIndex = false;
0591: }
0592: }
0593:
0594: if (!SystemInfo.isJdk15Above()) {
0595: // a workaround for Swing bug
0596: if (tabIndex == getTabCount() - 2) {
0597: setSelectedIndex(getTabCount() - 1);
0598: }
0599: }
0600:
0601: setAutoRequestFocus(old);
0602: setSelectedIndex(tabIndex);
0603: } finally {
0604: _suppressStateChangedEvents = false;
0605:
0606: if (shouldChangeFocus) {
0607: Runnable runnable = new Runnable() {
0608: public void run() {
0609: if (!requestFocusForVisibleComponent()) {
0610: requestFocusInWindow();
0611: }
0612: }
0613: };
0614: SwingUtilities.invokeLater(runnable);
0615: }
0616: }
0617: }
0618:
0619: protected boolean requestFocusForVisibleComponent() {
0620: Component visibleComponent = getSelectedComponent();
0621: Component lastFocused = getLastFocusedComponent(visibleComponent);
0622: if (lastFocused != null && lastFocused.requestFocusInWindow()) {
0623: return true;
0624: } else {
0625: // Focus the next component in the focus cycle after the tab.
0626: Container nearestRoot = (isFocusCycleRoot()) ? this
0627: : getFocusCycleRootAncestor();
0628: if (nearestRoot == null) {
0629: return false;
0630: }
0631: Component comp = nearestRoot.getFocusTraversalPolicy()
0632: .getComponentAfter(nearestRoot, this );
0633: if (comp != null && comp.requestFocusInWindow()) {
0634: return true;
0635: } else {
0636: return JideSwingUtilities
0637: .compositeRequestFocus(visibleComponent);
0638: }
0639: }
0640: }
0641:
0642: class IgnoreableSingleSelectionModel extends
0643: DefaultSingleSelectionModel {
0644: @Override
0645: protected void fireStateChanged() {
0646: if (!_suppressStateChangedEvents) {
0647: super .fireStateChanged();
0648: }
0649: }
0650: }
0651:
0652: /**
0653: * Gets tab height.
0654: *
0655: * @return height of tab
0656: */
0657: public int getTabHeight() {
0658: if (getTabPlacement() == TOP || getTabPlacement() == BOTTOM) {
0659: return ((JideTabbedPaneUI) getUI()).getTabPanel()
0660: .getHeight();
0661: } else {
0662: return ((JideTabbedPaneUI) getUI()).getTabPanel()
0663: .getWidth();
0664: }
0665: }
0666:
0667: /**
0668: * Returns true if you want right click on unselected tab will select that tab.
0669: *
0670: * @return true if right click on unselected tab will select that tab
0671: */
0672: public boolean isRightClickSelect() {
0673: return _rightClickSelect;
0674: }
0675:
0676: /**
0677: * Sets if you want right click on unselected tab will select that tab.
0678: *
0679: * @param rightClickSelect true if right click on unselected tab will select that tab
0680: */
0681: public void setRightClickSelect(boolean rightClickSelect) {
0682: _rightClickSelect = rightClickSelect;
0683: }
0684:
0685: public int getTabAtLocation(int x, int y) {
0686: int tabCount = getTabCount();
0687: for (int i = 0; i < tabCount; i++) {
0688: if (getUI().getTabBounds(this , i).contains(x, y)) {
0689: return i;
0690: }
0691: }
0692: return -1;
0693: }
0694:
0695: /**
0696: * If the grip is visible.
0697: *
0698: * @return true if grip is visible
0699: */
0700: public boolean isShowGripper() {
0701: return _showGripper;
0702: }
0703:
0704: /**
0705: * Sets the visibility of grip.
0706: *
0707: * @param showGripper true to show grip
0708: */
0709: public void setShowGripper(boolean showGripper) {
0710: boolean oldShowGripper = _showGripper;
0711: if (oldShowGripper != showGripper) {
0712: _showGripper = showGripper;
0713: firePropertyChange(GRIPPER_PROPERTY, oldShowGripper,
0714: _showGripper);
0715: }
0716: }
0717:
0718: /**
0719: * Checks if the icon will be shown on tab.
0720: *
0721: * @return true if the icon will be shown on tab.
0722: */
0723: public boolean isShowIconsOnTab() {
0724: return _showIconsOnTab;
0725: }
0726:
0727: /**
0728: * Sets to true if the icon will be shown on tab. The value set to this
0729: * method will be used only when isUseDefaultShowIconsOnTab() returns false.
0730: *
0731: * @param showIconsOnTab true or false.
0732: */
0733: public void setShowIconsOnTab(boolean showIconsOnTab) {
0734: boolean oldShowIconsOnTab = _showIconsOnTab;
0735: if (oldShowIconsOnTab != showIconsOnTab) {
0736: _showIconsOnTab = showIconsOnTab;
0737: firePropertyChange(SHOW_ICONS_PROPERTY, oldShowIconsOnTab,
0738: _showIconsOnTab);
0739: }
0740: }
0741:
0742: /**
0743: * If the return is true, the value set to setShowIconsOnTab() will be ignored.
0744: *
0745: * @return if use default value from UIDefaults in L&F.
0746: */
0747: public boolean isUseDefaultShowIconsOnTab() {
0748: return _useDefaultShowIconsOnTab;
0749: }
0750:
0751: /**
0752: * Set if use the default value from UIDefaults.
0753: *
0754: * @param useDefaultShowIconsOnTab true or false.
0755: */
0756: public void setUseDefaultShowIconsOnTab(
0757: boolean useDefaultShowIconsOnTab) {
0758: boolean oldUseDefaultShowIconsOnTab = _useDefaultShowIconsOnTab;
0759: if (oldUseDefaultShowIconsOnTab != useDefaultShowIconsOnTab) {
0760: _useDefaultShowIconsOnTab = useDefaultShowIconsOnTab;
0761: firePropertyChange(USE_DEFAULT_SHOW_ICONS_PROPERTY,
0762: oldUseDefaultShowIconsOnTab,
0763: _useDefaultShowIconsOnTab);
0764: }
0765: }
0766:
0767: /**
0768: * Checks if the close button will be shown on tab.
0769: *
0770: * @return true if close button will be shown on tab.
0771: */
0772: public boolean isShowCloseButtonOnTab() {
0773: return _showCloseButtonOnTab;
0774: }
0775:
0776: /**
0777: * Sets to true if the close button will be shown on tab. The value set to this
0778: * method will be used only when isUseDefaultShowCloseButtonOnTab() returns false.
0779: * You also need to setShowCloseButton(true) if you want to setShowCloseButtonOnTab(true).
0780: *
0781: * @param showCloseButtonOnTab true or false.
0782: */
0783: public void setShowCloseButtonOnTab(boolean showCloseButtonOnTab) {
0784: boolean oldShowCloseButtonOnTab = _showCloseButtonOnTab;
0785: if (oldShowCloseButtonOnTab != showCloseButtonOnTab) {
0786: _showCloseButtonOnTab = showCloseButtonOnTab;
0787: firePropertyChange(SHOW_CLOSE_BUTTON_ON_TAB_PROPERTY,
0788: oldShowCloseButtonOnTab, _showCloseButtonOnTab);
0789: }
0790: }
0791:
0792: /**
0793: * If the return is true, the value set to setShowCloseButtonOnTab() will be ignored.
0794: *
0795: * @return if use default value from UIDefaults in L&F.
0796: */
0797: public boolean isUseDefaultShowCloseButtonOnTab() {
0798: return _useDefaultShowCloseButtonOnTab;
0799: }
0800:
0801: /**
0802: * Set if use the default value from UIDefaults.
0803: *
0804: * @param useDefaultShowCloseButtonOnTab true or false.
0805: */
0806: public void setUseDefaultShowCloseButtonOnTab(
0807: boolean useDefaultShowCloseButtonOnTab) {
0808: boolean oldUseDefaultShowCloseButtonOnTab = _useDefaultShowCloseButtonOnTab;
0809: if (oldUseDefaultShowCloseButtonOnTab != useDefaultShowCloseButtonOnTab) {
0810: _useDefaultShowCloseButtonOnTab = useDefaultShowCloseButtonOnTab;
0811: firePropertyChange(
0812: USE_DEFAULT_SHOW_CLOSE_BUTTON_ON_TAB_PROPERTY,
0813: oldUseDefaultShowCloseButtonOnTab,
0814: _useDefaultShowCloseButtonOnTab);
0815: }
0816: }
0817:
0818: // below is the code to allow editing the tab title directly
0819: transient protected boolean _tabEditingAllowed = false;
0820:
0821: /**
0822: * Sets the value if the tab editing is allowed. Tab editing allows user to edit
0823: * the tab title directly by double clicking on the tab.
0824: *
0825: * @param allowed true or false.
0826: */
0827: public void setTabEditingAllowed(boolean allowed) {
0828: _tabEditingAllowed = allowed;
0829: }
0830:
0831: /**
0832: * Checks if the tab editing is allowed.
0833: *
0834: * @return true if tab editing is allowed. Otherwise false.
0835: */
0836: public boolean isTabEditingAllowed() {
0837: return _tabEditingAllowed
0838: && getTabLayoutPolicy() == SCROLL_TAB_LAYOUT;
0839: }
0840:
0841: /**
0842: * If close button is visible.
0843: *
0844: * @return true if the close button is visible.
0845: */
0846: public boolean isShowCloseButton() {
0847: return _showCloseButton;
0848: }
0849:
0850: /**
0851: * Sets if the close button is visible. Close button can be either
0852: * side by side with scroll buttons, or on each tab. If you call setShowCloseButton(false), it will
0853: * hide close buttons for both cases.
0854: *
0855: * @param showCloseButton true or false.
0856: */
0857: public void setShowCloseButton(boolean showCloseButton) {
0858: boolean oldShowCloseButton = _showCloseButton;
0859: if (oldShowCloseButton != showCloseButton) {
0860: _showCloseButton = showCloseButton;
0861: firePropertyChange(SHOW_CLOSE_BUTTON_PROPERTY,
0862: oldShowCloseButton, _showCloseButton);
0863: }
0864: }
0865:
0866: /**
0867: * If the tab area is visible.
0868: *
0869: * @return true if the tab area is visible.
0870: */
0871: public boolean isShowTabArea() {
0872: return _showTabArea;
0873: }
0874:
0875: /**
0876: * Sets if the tab area is visible. If not visible, you can programatically
0877: * call setSelectedIndex to change ta. User will not be able to do it by clicking on
0878: * tabs since they are not visible.
0879: *
0880: * @param showTabArea true or false.
0881: */
0882: public void setShowTabArea(boolean showTabArea) {
0883: boolean oldShowTabArea = _showTabArea;
0884: if (oldShowTabArea != showTabArea) {
0885: _showTabArea = showTabArea;
0886: firePropertyChange(SHOW_TAB_AREA_PROPERTY, oldShowTabArea,
0887: _showTabArea);
0888: }
0889: }
0890:
0891: /**
0892: * If the tab content is visible.
0893: *
0894: * @return true if the tab content is visible.
0895: */
0896: public boolean isShowTabContent() {
0897: return _showTabContent;
0898: }
0899:
0900: /**
0901: * Sets if the tab content is visible.
0902: *
0903: * @param showTabContent true or false.
0904: */
0905: public void setShowTabContent(boolean showTabContent) {
0906: boolean oldShowTabContent = _showTabContent;
0907: if (oldShowTabContent != showTabContent) {
0908: _showTabContent = showTabContent;
0909: firePropertyChange(SHOW_TAB_CONTENT_PROPERTY,
0910: oldShowTabContent, _showTabContent);
0911: }
0912: }
0913:
0914: /**
0915: * Gets the string converter that converts the tab title to the display title.
0916: *
0917: * @return the converter that converts the tab title to the display title.
0918: */
0919: public StringConverter getStringConverter() {
0920: return _stringConverter;
0921: }
0922:
0923: /**
0924: * Sets the string converter.
0925: *
0926: * @param stringConverter the StringConverter.
0927: */
0928: public void setStringConverter(StringConverter stringConverter) {
0929: _stringConverter = stringConverter;
0930: }
0931:
0932: /**
0933: * Gets the display title. Display title is result of using string converter that converts from
0934: * the title to a display title. There is no setter for display title. You control the value by using
0935: * a different string converter.
0936: *
0937: * @param index
0938: * @return the display title.
0939: */
0940: public String getDisplayTitleAt(int index) {
0941: if (_stringConverter != null) {
0942: return _stringConverter.convert(super .getTitleAt(index));
0943: } else {
0944: return super .getTitleAt(index);
0945: }
0946: }
0947:
0948: /**
0949: * If the active tab is in bold.
0950: *
0951: * @return if the active tab is in bold.
0952: */
0953: public boolean isBoldActiveTab() {
0954: return _boldActiveTab;
0955: }
0956:
0957: /**
0958: * Sets if the active tab is in bold.
0959: *
0960: * @param boldActiveTab
0961: */
0962: public void setBoldActiveTab(boolean boldActiveTab) {
0963: boolean old = _boldActiveTab;
0964: if (old != boldActiveTab) {
0965: _boldActiveTab = boldActiveTab;
0966: firePropertyChange(BOLDACTIVETAB_PROPERTY, old,
0967: _boldActiveTab);
0968: }
0969: }
0970:
0971: @Override
0972: public void removeTabAt(int index) {
0973:
0974: // There is a bug in JTabbedPane removeTabAt(int index) method,
0975: // if the selected index is not the last one, and it is deleted, no ChangeEvent is fired
0976: int tabCount = getTabCount();
0977: int selected = getSelectedIndex();
0978: boolean enforce = false;
0979: if (selected == index && selected < tabCount - 1) {
0980: enforce = true;
0981: }
0982:
0983: boolean contains = false;
0984: String titleAt = getTitleAt(index);
0985: if (_closableMap.containsKey(titleAt)) {
0986: contains = true;
0987: }
0988: Component component = getComponentAt(index);
0989: super .removeTabAt(index);
0990: if (contains) {
0991: _closableMap.remove(titleAt);
0992: }
0993: if (component != null) {
0994: // JTabbedPane allows a null component, but doesn't really support it.
0995: PageLastFocusTracker tracker = (PageLastFocusTracker) _pageLastFocusTrackers
0996: .get(component);
0997: _pageLastFocusTrackers.remove(component);
0998: if (tracker != null) {
0999: tracker.setHeighestComponent(null); // Clear its listeners
1000: }
1001: }
1002:
1003: // We need to fire events
1004: if (enforce) {
1005: try {
1006: fireStateChanged();
1007: } catch (Throwable th) {
1008: th.printStackTrace();
1009: }
1010: }
1011: }
1012:
1013: @Override
1014: public void setTitleAt(int index, String title) {
1015: boolean contains = false;
1016: if (_closableMap.containsKey(getTitleAt(index))) {
1017: contains = true;
1018: }
1019: super .setTitleAt(index, title);
1020: if (contains) {
1021: _closableMap.put(title, "");
1022: }
1023: }
1024:
1025: /**
1026: * Checks if the tab at tabIndex should show the close button.
1027: * This is only a valid if showCloseButtonOnTab attribute is true.
1028: * <p/>
1029: * By default, this method always return true. Subclass can override
1030: * this method to return a different value.
1031: *
1032: * @param tabIndex
1033: * @throws IndexOutOfBoundsException if index is out of range
1034: * (index < 0 || index >= tab count)
1035: */
1036: public boolean isTabClosableAt(int tabIndex) {
1037: return !_closableMap.containsKey(tabIndex);
1038: }
1039:
1040: /**
1041: * Checks if the tab at tabIndex should show the close button.
1042: * This is only a valid if showCloseButtonOnTab attribute is true.
1043: * <p/>
1044: * By default, this method always return true. Subclass can override
1045: * this method to return a different value.
1046: * <p/>
1047: * Please note, this attribute has effect only when {@link #isShowCloseButtonOnTab()} return true.
1048: *
1049: * @param tabIndex
1050: * @throws IndexOutOfBoundsException if index is out of range
1051: * (index < 0 || index >= tab count)
1052: */
1053: public void setTabClosableAt(int tabIndex, boolean closble) {
1054: if (closble) {
1055: _closableMap.remove(tabIndex);
1056: } else {
1057: _closableMap.put(tabIndex, Boolean.FALSE);
1058: }
1059: firePropertyChange(TAB_CLOSABLE_PROPERTY, !closble, closble);
1060: }
1061:
1062: protected Hashtable getPageLastFocusTrackers() {
1063: return _pageLastFocusTrackers;
1064: }
1065:
1066: /**
1067: * Gets the last focused component of a particular page.
1068: *
1069: * @param pageComponent
1070: * @return the last focused component of a particular page.
1071: */
1072: public Component getLastFocusedComponent(Component pageComponent) {
1073: if (pageComponent == null) {
1074: return null;
1075: }
1076: PageLastFocusTracker tracker = (PageLastFocusTracker) (getPageLastFocusTrackers()
1077: .get(pageComponent));
1078: return ((tracker != null) ? tracker.getLastFocusedComponent()
1079: : null);
1080: }
1081:
1082: /**
1083: * Overridden to add a <code>PageLastFocusTracker</code> to each page, used to
1084: * update the page's last focused component.
1085: */
1086: @Override
1087: public void insertTab(String title, Icon icon, Component component,
1088: String tip, int index) {
1089: super .insertTab(title, icon, component, tip, index);
1090:
1091: if (component != null) {
1092: // JTabbedPane allows a null component, but doesn't really support it.
1093: _pageLastFocusTrackers.put(component,
1094: new PageLastFocusTracker(component));
1095: }
1096: }
1097:
1098: protected class PageLastFocusTracker extends JideFocusTracker {
1099: // keep track of last focused component
1100: private Component _lastFocusedComponent;
1101:
1102: private FocusListener _lastFocusedListener;
1103:
1104: protected PageLastFocusTracker(Component pageComp) {
1105: this .setHeighestComponent(pageComp);
1106: }
1107:
1108: protected Component getLastFocusedComponent() {
1109: return _lastFocusedComponent;
1110: }
1111:
1112: @Override
1113: public void setHeighestComponent(Component compHeighest) {
1114: if (compHeighest == null) {
1115: if (_lastFocusedListener != null) {
1116: this .removeFocusListener(_lastFocusedListener);
1117: _lastFocusedListener = null;
1118: }
1119: } else {
1120: if (_lastFocusedListener == null) {
1121: _lastFocusedListener = new FocusAdapter() {
1122: @Override
1123: public void focusGained(FocusEvent e) {
1124: _lastFocusedComponent = e.getComponent();
1125: }
1126: };
1127: this .addFocusListener(_lastFocusedListener);
1128: }
1129: }
1130: super .setHeighestComponent(compHeighest);
1131: }
1132: }
1133:
1134: /**
1135: * Gets the font for selected tab.
1136: *
1137: * @return the font for selected tab.
1138: */
1139: public Font getSelectedTabFont() {
1140: return _selectedTabFont;
1141: }
1142:
1143: /**
1144: * Sets the font for selected tab.
1145: *
1146: * @param selectedTabFont new font for selected tab.
1147: */
1148: public void setSelectedTabFont(Font selectedTabFont) {
1149: _selectedTabFont = selectedTabFont;
1150: }
1151:
1152: public int getColorTheme() {
1153: if (_colorTheme == COLOR_THEME_DEFAULT) {
1154: return getDefaultColorTheme();
1155: } else {
1156: return _colorTheme;
1157: }
1158: }
1159:
1160: public int getDefaultColorTheme() {
1161: return UIDefaultsLookup
1162: .getInt("JideTabbedPane.defaultTabColorTheme");
1163: }
1164:
1165: public void setColorTheme(int colorTheme) {
1166: int old = _colorTheme;
1167: if (old != colorTheme) {
1168: _colorTheme = colorTheme;
1169: firePropertyChange(PROPERTY_COLOR_THEME, old, colorTheme);
1170: }
1171: }
1172:
1173: public int getTabResizeMode() {
1174: if (_tabResizeMode == RESIZE_MODE_DEFAULT) {
1175: return getDefaultTabResizeMode();
1176: } else {
1177: return _tabResizeMode;
1178: }
1179: }
1180:
1181: /**
1182: * Sets the tab resize mode. There are five resize modes. - {@link #RESIZE_MODE_DEFAULT},
1183: * {@link #RESIZE_MODE_NONE}, {@link #RESIZE_MODE_FIT}, {@link #RESIZE_MODE_FIXED} and {@link #RESIZE_MODE_COMPRESSED}.
1184: *
1185: * @param resizeMode the new resize mode.
1186: */
1187: public void setTabResizeMode(int resizeMode) {
1188: int old = _tabResizeMode;
1189: if (old != resizeMode) {
1190: _tabResizeMode = resizeMode;
1191: firePropertyChange(PROPERTY_TAB_RESIZE_MODE, old,
1192: resizeMode);
1193: }
1194: }
1195:
1196: public int getDefaultTabResizeMode() {
1197: return UIDefaultsLookup
1198: .getInt("JideTabbedPane.defaultResizeMode");
1199: }
1200:
1201: public int getTabShape() {
1202: if (_tabShape == SHAPE_DEFAULT) {
1203: return getDefaultTabStyle();
1204: } else {
1205: return _tabShape;
1206: }
1207: }
1208:
1209: public int getDefaultTabStyle() {
1210: return UIDefaultsLookup
1211: .getInt("JideTabbedPane.defaultTabShape");
1212: }
1213:
1214: public void setTabShape(int tabShape) {
1215: int old = _tabShape;
1216: if (old != tabShape) {
1217: _tabShape = tabShape;
1218: firePropertyChange(PROPERTY_TAB_SHAPE, old, _tabShape);
1219: }
1220: }
1221:
1222: /**
1223: * Sets the tab leading component. The tab leading component will appear before the tabs in the tab area.
1224: * Please note, you must implement UIResource for the component you want to use as tab leading component.
1225: *
1226: * @param component
1227: * @throws IllegalArgumentException if the component doesn't implement UIResource.
1228: */
1229: public void setTabLeadingComponent(Component component) {
1230: if (component != null) {
1231: if (!(component instanceof UIResource)) {
1232: throw new IllegalArgumentException(
1233: "TabLeadingComponent must implement javax.swing.plaf.UIResource interface.");
1234: }
1235: component.setSize(component.getPreferredSize());
1236: component.setVisible(true);
1237: }
1238: Component old = _tabLeadingComponent;
1239: _tabLeadingComponent = component;
1240: firePropertyChange(PROPERTY_TAB_LEADING_COMPONENT, old,
1241: component);
1242: }
1243:
1244: public Component getTabLeadingComponent() {
1245: return _tabLeadingComponent;
1246: }
1247:
1248: /**
1249: * Sets the tab trailing component. The tab trailing component will appear after the tabs in the tab area.
1250: * Please note, you must implement UIResource for the component you want to use as tab trailing component.
1251: *
1252: * @param component
1253: * @throws IllegalArgumentException if the component doesn't implement UIResource.
1254: */
1255: public void setTabTrailingComponent(Component component) {
1256: if (component != null) {
1257: if (!(component instanceof UIResource)) {
1258: throw new IllegalArgumentException(
1259: "TabLeadingComponent must implement javax.swing.plaf.UIResource interface.");
1260: }
1261: component.setSize(component.getPreferredSize());
1262: component.setVisible(true);
1263: }
1264: Component old = _tabTrailingComponent;
1265: _tabTrailingComponent = component;
1266: firePropertyChange(PROPERTY_TAB_TRAILING_COMPONENT, old,
1267: component);
1268: }
1269:
1270: public Component getTabTrailingComponent() {
1271: return _tabTrailingComponent;
1272: }
1273:
1274: public boolean isShowCloseButtonOnSelectedTab() {
1275: return _showCloseButtonOnSelectedTab;
1276: }
1277:
1278: /**
1279: * Shows the close button on the selected tab only.
1280: * You also need to setShowCloseButtonOnTab(true) and setShowCloseButton(true) if you want to setShowCloseButtonOnSelectedTab(true).
1281: *
1282: * @param i
1283: */
1284: public void setShowCloseButtonOnSelectedTab(boolean i) {
1285: _showCloseButtonOnSelectedTab = i;
1286: }
1287:
1288: private ColorProvider _tabColorProvider;
1289:
1290: /**
1291: * An interface to provide colors for tab background and foreground.
1292: */
1293: public static interface ColorProvider {
1294: /**
1295: * Gets the tab background for the tab at the specified index.
1296: *
1297: * @param tabIndex
1298: * @return the tab background for the tab at the specified index.
1299: */
1300: Color getBackgroundAt(int tabIndex);
1301:
1302: /**
1303: * Gets the tab foreground for the tab at the specified index.
1304: *
1305: * @param tabIndex
1306: * @return the tab foreground for the tab at the specified index.
1307: */
1308: Color getForegroudAt(int tabIndex);
1309:
1310: /**
1311: * Gets the gradient ratio. We will use this ratio to provide
1312: * another color in order to paint gradient.
1313: *
1314: * @param tabIndex
1315: * @return the gradient ratio. The value should be between 0 and 1.
1316: * 0 will produce the darkest and color and 1 will produce the lighest color.
1317: * 0.5 will provide the same color.
1318: */
1319: float getGradientRatio(int tabIndex);
1320: }
1321:
1322: /**
1323: * A ColorProvider that can supports gradient tab background.
1324: * The ColorProvider can also do gradient but the other color has to be be a lighter
1325: * or darker version of the color of getBackgroundAt. GradientColorProvider
1326: * allows you to specify an indenpendent color as the start color.
1327: */
1328: public static interface GradientColorProvider extends ColorProvider {
1329: /**
1330: * Gets the tab background at the top (or other direction depending on the tab placement) of the tab.
1331: * The JideTabbedPaneUI will paint a gradient using this color and the color of getBackgroundAt.
1332: *
1333: * @return the top background color.
1334: */
1335: Color getTopBackgroundAt(int tabIndex);
1336: }
1337:
1338: private static Color[] ONENOTE_COLORS = { new Color(138, 168, 228), // blue
1339: new Color(238, 149, 151), // pink
1340: new Color(180, 158, 222), // purple
1341: new Color(145, 186, 174), // cyan
1342: new Color(246, 176, 120), // gold
1343: new Color(255, 216, 105), // yellow
1344: new Color(183, 201, 151) // green
1345: };
1346:
1347: public static ColorProvider ONENOTE_COLOR_PROVIDER = new OneNoteColorProvider();
1348:
1349: private static class OneNoteColorProvider implements ColorProvider {
1350: public Color getBackgroundAt(int index) {
1351: return ONENOTE_COLORS[index % ONENOTE_COLORS.length];
1352: }
1353:
1354: public Color getForegroudAt(int index) {
1355: return Color.BLACK;
1356: }
1357:
1358: public float getGradientRatio(int tabIndex) {
1359: return 0.86f;
1360: }
1361:
1362: }
1363:
1364: /**
1365: * Gets the tab color provider.
1366: *
1367: * @return tab color provider.
1368: */
1369: public ColorProvider getTabColorProvider() {
1370: return _tabColorProvider;
1371: }
1372:
1373: /**
1374: * Sets the tab color provider.It allows you to set the background color of each tab. The reason
1375: * to use this way instead of {@link #setBackgroundAt(int,java.awt.Color)} method is because
1376: * this way queries the color. So it can support unlimited number of tabs. When you don't know
1377: * exactly how many tabs it will be, this way can still handle it very well.
1378: * There is {@link #ONENOTE_COLOR_PROVIDER} which provides the tab color as you see in Microsoft OneNote 2003.
1379: * You can also define your own ColorProvider to fit your application color theme.
1380: *
1381: * @param tabColorProvider
1382: */
1383: public void setTabColorProvider(ColorProvider tabColorProvider) {
1384: ColorProvider old = _tabColorProvider;
1385: if (old != tabColorProvider) {
1386: _tabColorProvider = tabColorProvider;
1387: firePropertyChange(PROPERTY_TAB_COLOR_PROVIDER, old,
1388: tabColorProvider);
1389: }
1390: }
1391:
1392: /**
1393: * Starts tab editing. This works only when {@link #setTabEditingAllowed(boolean)} is set to true.
1394: *
1395: * @param tabIndex
1396: */
1397: public void editTabAt(int tabIndex) {
1398: boolean started = ((JideTabbedPaneUI) getUI())
1399: .editTabAt(tabIndex);
1400: if (started) {
1401: fireTabEditing(TabEditingEvent.TAB_EDITING_STARTED,
1402: tabIndex, getTitleAt(tabIndex), null);
1403: }
1404: }
1405:
1406: /**
1407: * Checks if tab is in editing mode.
1408: *
1409: * @return true if editing.
1410: */
1411: public boolean isTabEditing() {
1412: return ((JideTabbedPaneUI) getUI()).isTabEditing();
1413: }
1414:
1415: public void stopTabEditing() {
1416: int tabIndex = getEditingTabIndex();
1417: if (tabIndex != -1) {
1418: String oldTitle = getTitleAt(tabIndex);
1419: ((JideTabbedPaneUI) getUI()).stopTabEditing();
1420: String newTitle = getTitleAt(tabIndex);
1421: fireTabEditing(TabEditingEvent.TAB_EDITING_STOPPED,
1422: tabIndex, oldTitle, newTitle);
1423: }
1424: }
1425:
1426: public void cancelTabEditing() {
1427: int tabIndex = getEditingTabIndex();
1428: if (tabIndex != -1) {
1429: ((JideTabbedPaneUI) getUI()).cancelTabEditing();
1430: fireTabEditing(TabEditingEvent.TAB_EDITING_STARTED,
1431: tabIndex, getTitleAt(tabIndex),
1432: getTitleAt(tabIndex));
1433: }
1434: }
1435:
1436: public int getEditingTabIndex() {
1437: return ((JideTabbedPaneUI) getUI()).getEditingTabIndex();
1438: }
1439:
1440: protected PropertyChangeListener _focusChangeListener;
1441:
1442: protected PropertyChangeListener createFocusChangeListener() {
1443: return new PropertyChangeListener() {
1444: public void propertyChange(PropertyChangeEvent evt) {
1445: final boolean hadFocus = JideTabbedPane.this
1446: .isAncestorOf((Component) evt.getOldValue())
1447: || JideTabbedPane.this == evt.getOldValue();
1448: boolean hasFocus = JideTabbedPane.this == evt
1449: .getNewValue()
1450: || JideTabbedPane.this .hasFocusComponent();
1451: if (hasFocus != hadFocus) {
1452: repaintTabAreaAndContentBorder();
1453: }
1454: }
1455: };
1456: }
1457:
1458: /**
1459: * Repaints the tab area and the content border if any. This is mainly for the focus border in JideTabbedPane Office2003 and Eclipse3x style.
1460: */
1461: public void repaintTabAreaAndContentBorder() {
1462: int delay = 200;
1463: ((JideTabbedPaneUI) getUI()).getTabPanel().repaint(delay);
1464:
1465: if (UIDefaultsLookup.get("JideTabbedPane.contentBorderInsets") == null) {
1466: LookAndFeelFactory.installJideExtension();
1467: }
1468:
1469: Insets contentinsets = UIDefaultsLookup
1470: .getInsets("JideTabbedPane.contentBorderInsets");
1471: if (contentinsets != null
1472: && (contentinsets.top != 0 || contentinsets.bottom != 0
1473: || contentinsets.left != 0 || contentinsets.right != 0)) {
1474: Insets insets = new Insets(0, 0, 0, 0);
1475: BasicJideTabbedPaneUI.rotateInsets(contentinsets, insets,
1476: tabPlacement);
1477: if (insets.top != 0) {
1478: repaint(delay, 0, 0, getWidth(), insets.top);
1479: }
1480: if (insets.left != 0) {
1481: repaint(delay, 0, 0, insets.left, getHeight());
1482: }
1483: if (insets.right != 0) {
1484: repaint(delay, getWidth() - insets.right, 0,
1485: insets.right, getHeight());
1486: }
1487: if (insets.bottom != 0) {
1488: repaint(delay, 0, getHeight() - insets.bottom,
1489: getWidth(), insets.bottom);
1490: }
1491: }
1492: }
1493:
1494: @Override
1495: public void addNotify() {
1496: super .addNotify();
1497: if (_focusChangeListener == null) {
1498: _focusChangeListener = createFocusChangeListener();
1499: KeyboardFocusManager.getCurrentKeyboardFocusManager()
1500: .addPropertyChangeListener("focusOwner",
1501: _focusChangeListener);
1502: }
1503:
1504: }
1505:
1506: @Override
1507: public void removeNotify() {
1508: super .removeNotify();
1509: if (_focusChangeListener != null) {
1510: KeyboardFocusManager.getCurrentKeyboardFocusManager()
1511: .removePropertyChangeListener("focusOwner",
1512: _focusChangeListener);
1513: _focusChangeListener = null;
1514: }
1515: }
1516:
1517: /**
1518: * Gets the tab list cell renderer. This renderer is used to render the list in the popup when tab list button is pressed.
1519: *
1520: * @return the tab list cell renderer.
1521: */
1522: public ListCellRenderer getTabListCellRenderer() {
1523: if (_tabListCellRenderer != null) {
1524: return _tabListCellRenderer;
1525: } else {
1526: return new TabListCellRenderer();
1527: }
1528: }
1529:
1530: /**
1531: * The default tab list cell renderer used to renderer the list in the popup when tab list button is pressed.
1532: */
1533: public static class TabListCellRenderer extends
1534: DefaultListCellRenderer {
1535: @Override
1536: public Component getListCellRendererComponent(JList list,
1537: Object value, int index, boolean isSelected,
1538: boolean cellHasFocus) {
1539: if (value instanceof JideTabbedPane) {
1540: JideTabbedPane tabbedPane = (JideTabbedPane) value;
1541: String title = tabbedPane.getTitleAt(index);
1542: String tooltip = tabbedPane.getToolTipTextAt(index);
1543: Icon icon = tabbedPane.getIconAt(index);
1544: JLabel label = (JLabel) super
1545: .getListCellRendererComponent(list, title,
1546: index, isSelected, cellHasFocus);
1547: label.setToolTipText(tooltip);
1548: label.setIcon(icon);
1549: label.setEnabled(tabbedPane.isEnabledAt(index));
1550: return label;
1551: } else {
1552: return super .getListCellRendererComponent(list, value,
1553: index, isSelected, cellHasFocus);
1554: }
1555: }
1556: }
1557:
1558: /**
1559: * Sets the tab list cell renderer. This renderer is used to render the list in the popup when tab list button is pressed.
1560: * In this list cell renderer, the value will always be the JideTabbedPane. The index will tell you which tab it is.
1561: * See below for the default cell renderer we used.
1562: * <code><pre>
1563: * public static class TabListCellRenderer extends DefaultListCellRenderer {
1564: * public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
1565: * if (value instanceof JideTabbedPane) { // will always be true
1566: * JideTabbedPane tabbedPane = (JideTabbedPane) value;
1567: * String title = tabbedPane.getTitleAt(index);
1568: * Icon icon = tabbedPane.getIconAt(index);
1569: * JLabel label = (JLabel) super.getListCellRendererComponent(list, title, index, isSelected, cellHasFocus);
1570: * label.setIcon(icon);
1571: * return label;
1572: * }
1573: * else {
1574: * return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1575: * }
1576: * }
1577: * }
1578: * </code></pre>
1579: * You can create your own cell renderer either extending {@link TabListCellRenderer} or starting from scratch.
1580: *
1581: * @param tabListCellRenderer
1582: */
1583: public void setTabListCellRenderer(
1584: ListCellRenderer tabListCellRenderer) {
1585: _tabListCellRenderer = tabListCellRenderer;
1586: }
1587:
1588: /**
1589: * Checks if the JideTabbedPane has the focus component. If true, in some styles such as Office2003 style, we will
1590: * paint a background on the insets to indicate the tabbed pane has focus.
1591: *
1592: * @return true if the JideTabbedPane has the focus component. Otherwise false.
1593: */
1594: public boolean hasFocusComponent() {
1595: return JideSwingUtilities.isAncestorOfFocusOwner(this );
1596: }
1597:
1598: public Insets getContentBorderInsets() {
1599: return _contentBorderInsets;
1600: }
1601:
1602: /**
1603: * Sets the content border insets. It's the inserts around the JideTabbedPane's content. The direction of the insets
1604: * is when the tabs are on top. We will rotate it automatically when the tabs are on other direcitons.
1605: *
1606: * @param contentBorderInsets
1607: */
1608: public void setContentBorderInsets(Insets contentBorderInsets) {
1609: Insets old = _contentBorderInsets;
1610: _contentBorderInsets = contentBorderInsets;
1611: firePropertyChange(PROPERTY_CONTENT_BORDER_INSETS, old,
1612: _contentBorderInsets);
1613: }
1614:
1615: /**
1616: * Checks the dragOverDisabled property. By default it is false.
1617: *
1618: * @return true or false.
1619: * @see #setDragOverDisabled(boolean)
1620: */
1621: public boolean isDragOverDisabled() {
1622: return _dragOverDisabled;
1623: }
1624:
1625: /**
1626: * Sets the dragOverDisabled property. Default is false. It means when you drag something over an unselected tab, the tab will be selected
1627: * automatically. You may want to set it to true if you want to add your own drop listener to the tabs.
1628: *
1629: * @param dragOverDisabled
1630: */
1631: public void setDragOverDisabled(boolean dragOverDisabled) {
1632: boolean old = _dragOverDisabled;
1633: if (old != dragOverDisabled) {
1634: _dragOverDisabled = dragOverDisabled;
1635: firePropertyChange(PROPERTY_DRAG_OVER_DISABLED, old,
1636: dragOverDisabled);
1637: }
1638: }
1639:
1640: /**
1641: * Scroll the selected tab visible in case the tab is outside of the viewport.
1642: *
1643: * @param scrollLeft true to scroll the first tab visible first then scroll left to make
1644: * the selected tab visible. This will get a more consistent result.
1645: * If false, it will simple scroll the selected tab visible. Sometimes the
1646: * tab will appear as the first visible tab or the last visible tab depending on
1647: * the previous viewport position.
1648: */
1649: public void scrollSelectedTabToVisible(boolean scrollLeft) {
1650: ((JideTabbedPaneUI) getUI())
1651: .ensureActiveTabIsVisible(scrollLeft);
1652: }
1653:
1654: /**
1655: * Adds a <code>TabEditingListener</code> to this tabbedpane.
1656: *
1657: * @param l the <code>TabEditingListener</code> to add
1658: * @see #fireTabEditing
1659: * @see #removeTabEditingListener
1660: */
1661: public void addTabEditingListener(TabEditingListener l) {
1662: listenerList.add(TabEditingListener.class, l);
1663: }
1664:
1665: /**
1666: * Removes a <code>TabEditingListener</code> from this tabbedpane.
1667: *
1668: * @param l the <code>TabEditingListener</code> to remove
1669: * @see #fireTabEditing
1670: * @see #addTabEditingListener
1671: */
1672: public void removeTabEditingListener(TabEditingListener l) {
1673: listenerList.remove(TabEditingListener.class, l);
1674: }
1675:
1676: /**
1677: * Returns an array of all the <code>TabEditingListener</code>s added
1678: * to this <code>JTabbedPane</code> with <code>addTabEditingListener</code>.
1679: *
1680: * @return all of the <code>TabEditingListener</code>s added or an empty
1681: * array if no listeners have been added
1682: */
1683: public TabEditingListener[] getTabEditingListeners() {
1684: return listenerList.getListeners(TabEditingListener.class);
1685: }
1686:
1687: protected void fireTabEditing(int id, int index, String oldTitle,
1688: String newTitle) {
1689: if (LOGGER_EVENT.isLoggable(Level.FINE)) {
1690: switch (id) {
1691: case TabEditingEvent.TAB_EDITING_STARTED:
1692: LOGGER_EVENT.fine("TabEditing Started at tab \""
1693: + index + "\"; the current title is "
1694: + oldTitle);
1695: break;
1696: case TabEditingEvent.TAB_EDITING_STOPPED:
1697: LOGGER_EVENT.fine("TabEditing Stopped at tab \""
1698: + index + "\"; the old title is " + oldTitle
1699: + "; the new title is " + newTitle);
1700: break;
1701: case TabEditingEvent.TAB_EDITING_CANCELLED:
1702: LOGGER_EVENT.fine("TabEditing Cancelled at tab \""
1703: + index + "\"; the current title remains "
1704: + oldTitle);
1705: break;
1706: }
1707: }
1708: Object[] listeners = listenerList.getListenerList();
1709: for (int i = listeners.length - 2; i >= 0; i -= 2) {
1710: if (listeners[i] == TabEditingListener.class) {
1711: TabEditingEvent tabEditingEvent = new TabEditingEvent(
1712: this , id, index, oldTitle, newTitle);
1713: if (id == TabEditingEvent.TAB_EDITING_STARTED) {
1714: ((TabEditingListener) listeners[i + 1])
1715: .editingStarted(tabEditingEvent);
1716: } else if (id == TabEditingEvent.TAB_EDITING_CANCELLED) {
1717: ((TabEditingListener) listeners[i + 1])
1718: .editingCanceled(tabEditingEvent);
1719: } else if (id == TabEditingEvent.TAB_EDITING_STOPPED) {
1720: ((TabEditingListener) listeners[i + 1])
1721: .editingStopped(tabEditingEvent);
1722: }
1723: }
1724: }
1725: }
1726: }
|