0001: /*
0002: * Copyright 2000,2005 wingS development team.
0003: *
0004: * This file is part of wingS (http://wingsframework.org).
0005: *
0006: * wingS is free software; you can redistribute it and/or modify
0007: * it under the terms of the GNU Lesser General Public License
0008: * as published by the Free Software Foundation; either version 2.1
0009: * of the License, or (at your option) any later version.
0010: *
0011: * Please see COPYING for the complete licence.
0012: */
0013: package org.wings;
0014:
0015: import org.wings.plaf.TabbedPaneCG;
0016: import org.wings.style.CSSAttributeSet;
0017: import org.wings.style.CSSProperty;
0018: import org.wings.style.Selector;
0019: import org.wings.style.CSSStyleSheet;
0020:
0021: import javax.swing.*;
0022: import javax.swing.event.ChangeEvent;
0023: import javax.swing.event.ChangeListener;
0024:
0025: import java.awt.*;
0026: import java.io.Serializable;
0027: import java.util.ArrayList;
0028:
0029: /**
0030: * Shows one tab, usually a panel, at a time and allows switching between them.
0031: *
0032: * @author <a href="mailto:haaf@mercatis.de">Armin Haaf</a>,
0033: * <a href="mailto:andre.lison@general-bytes.com">Andre Lison</a>
0034: */
0035: public class STabbedPane extends SContainer implements
0036: LowLevelEventListener {
0037: /**
0038: * A Pseudo selector addressing the container area of this container.
0039: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0040: */
0041: public static final Selector SELECTOR_CONTENT = new Selector(
0042: "content area");
0043: /**
0044: * A Pseudo CSS selector addressing the area which contains the tab buttons.
0045: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0046: */
0047: public static final Selector SELECTOR_TABS = new Selector(
0048: "tab area");
0049:
0050: /**
0051: * A Pseudo CSS selector addressing the selected tab
0052: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0053: */
0054: public static final Selector SELECTOR_SELECTED_TAB = new Selector(
0055: "the selected tab");
0056:
0057: /**
0058: * A Pseudo CSS selector addressing the unselected tab
0059: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0060: */
0061: public static final Selector SELECTOR_UNSELECTED_TAB = new Selector(
0062: "an unselected tab");
0063:
0064: /**
0065: * A Pseudo CSS selector addressing the unselected tab
0066: * Refer to {@link SComponent#setAttribute(org.wings.style.Selector, org.wings.style.CSSProperty, String)}
0067: */
0068: public static final Selector SELECTOR_DISABLED_TAB = new Selector(
0069: "a disabled tab");
0070:
0071: /**
0072: * Where the tabs are placed.
0073: *
0074: * @see #setTabPlacement
0075: */
0076: protected int tabPlacement = SConstants.TOP;
0077:
0078: /**
0079: * The default selection model
0080: */
0081: protected SingleSelectionModel model;
0082:
0083: ArrayList pages = new ArrayList(2);
0084:
0085: /**
0086: * layout used to render the tabs. Only one tab is on top at a time.
0087: */
0088: final private SCardLayout card = new SCardLayout();
0089:
0090: /**
0091: * container for all tabs. The card layout shows always one on
0092: * top.
0093: */
0094: final private SContainer contents = new SContainer(card);
0095:
0096: /**
0097: * the maximum tabs per line
0098: */
0099: protected int maxTabsPerLine = -1;
0100:
0101: /**
0102: * Number of selected tab.
0103: */
0104: protected int selectedIndex = 0;
0105:
0106: /**
0107: * the newly selected index during a
0108: * lowlevelevent
0109: */
0110: private int lleChangedIndex = -1;
0111:
0112: /**
0113: * @see LowLevelEventListener#isEpochCheckEnabled()
0114: */
0115: private boolean epochCheckEnabled = true;
0116:
0117: /**
0118: * used to forward change events to change listeners of the tabbed pane
0119: */
0120: private final ChangeListener fwdChangeEvents = new ChangeListener() {
0121: public void stateChanged(ChangeEvent ce) {
0122: final int index = model.getSelectedIndex();
0123: if (index >= pages.size() || index == -1)
0124: return;
0125: card.show(((Page) pages.get(index)).component);
0126:
0127: fireStateChanged();
0128: reload();
0129: }
0130: };
0131:
0132: /**
0133: * Creates a new empty Tabbed Pane with the tabs at the top.
0134: *
0135: * @see #addTab
0136: */
0137: public STabbedPane() {
0138: this (SConstants.TOP);
0139: }
0140:
0141: /**
0142: * Creates an empty TabbedPane with the specified tab placement
0143: * of either: TOP, BOTTOM, LEFT, or RIGHT.
0144: *
0145: * @param tabPlacement the placement for the tabs relative to the content
0146: * @see #addTab
0147: */
0148: public STabbedPane(int tabPlacement) {
0149: setTabPlacement(tabPlacement);
0150: super .addComponent(contents, null, 0);
0151: setModel(new DefaultSingleSelectionModel());
0152: }
0153:
0154: /**
0155: * Return the background color.
0156: *
0157: * @return the background color
0158: */
0159: public Color getSelectionBackground() {
0160: return dynamicStyles == null
0161: || dynamicStyles.get(SELECTOR_SELECTED_TAB) == null ? null
0162: : CSSStyleSheet
0163: .getBackground((CSSAttributeSet) dynamicStyles
0164: .get(SELECTOR_SELECTED_TAB));
0165: }
0166:
0167: /**
0168: * Set the foreground color.
0169: *
0170: * @param color the new foreground color
0171: */
0172: public void setSelectionBackground(Color color) {
0173: setAttribute(SELECTOR_SELECTED_TAB,
0174: CSSProperty.BACKGROUND_COLOR, CSSStyleSheet
0175: .getAttribute(color));
0176: }
0177:
0178: /**
0179: * Return the foreground color.
0180: *
0181: * @return the foreground color
0182: */
0183: public Color getSelectionForeground() {
0184: return dynamicStyles == null
0185: || dynamicStyles.get(SELECTOR_SELECTED_TAB) == null ? null
0186: : CSSStyleSheet
0187: .getForeground((CSSAttributeSet) dynamicStyles
0188: .get(SELECTOR_SELECTED_TAB));
0189: }
0190:
0191: /**
0192: * Set the foreground color.
0193: *
0194: * @param color the new foreground color
0195: */
0196: public void setSelectionForeground(Color color) {
0197: setAttribute(SELECTOR_SELECTED_TAB, CSSProperty.COLOR,
0198: CSSStyleSheet.getAttribute(color));
0199: }
0200:
0201: /**
0202: * Set the font.
0203: *
0204: * @param font the new font
0205: */
0206: public void setSelectionFont(SFont font) {
0207: setAttributes(SELECTOR_SELECTED_TAB, CSSStyleSheet
0208: .getAttributes(font));
0209: }
0210:
0211: /**
0212: * Return the font.
0213: *
0214: * @return the font
0215: */
0216: public SFont getSelectionFont() {
0217: return dynamicStyles == null
0218: || dynamicStyles.get(SELECTOR_SELECTED_TAB) == null ? null
0219: : CSSStyleSheet.getFont((CSSAttributeSet) dynamicStyles
0220: .get(SELECTOR_SELECTED_TAB));
0221: }
0222:
0223: /**
0224: * Add a listener to the list of change listeners.
0225: * ChangeListeners are notified, when the tab selection changes.
0226: *
0227: * @param cl add to listener list
0228: */
0229: public void addChangeListener(ChangeListener cl) {
0230: addEventListener(ChangeListener.class, cl);
0231: }
0232:
0233: /**
0234: * Remove listener from the list of change listeners.
0235: * ChangeListeners are notified, when the tab selection changes.
0236: *
0237: * @param cl remove from listener list
0238: */
0239: public void removeChangeListener(ChangeListener cl) {
0240: removeEventListener(ChangeListener.class, cl);
0241: }
0242:
0243: /**
0244: * Fire ChangeEvents at all registered change listeners.
0245: */
0246: protected void fireStateChanged() {
0247: ChangeEvent event = null;
0248:
0249: // maybe the better way to do this is to user the getListenerList
0250: // and iterate through all listeners, this saves the creation of
0251: // an array but it must cast to the apropriate listener
0252: Object[] listeners = getListenerList();
0253: for (int i = listeners.length - 2; i >= 0; i -= 2) {
0254: if (listeners[i] == ChangeListener.class) {
0255: // Lazily create the event:
0256: if (event == null)
0257: event = new ChangeEvent(this );
0258: ((ChangeListener) listeners[i + 1]).stateChanged(event);
0259: }
0260: }
0261: }
0262:
0263: /**
0264: * Returns the placement of the tabs for this tabbedpane.
0265: *
0266: * @see #setTabPlacement
0267: */
0268: public int getTabPlacement() {
0269: return tabPlacement;
0270: }
0271:
0272: /**
0273: * Sets the tab placement for this tabbedpane.
0274: * Possible values are:<ul>
0275: * <li>SConstants.TOP
0276: * <li>SConstants.BOTTOM
0277: * <li>SConstants.LEFT
0278: * <li>SConstants.RIGHT
0279: * </ul>
0280: * The default value is TOP.
0281: *
0282: * @param tabPlacement the placement for the tabs relative to the content
0283: */
0284: public void setTabPlacement(int tabPlacement) {
0285: if (tabPlacement != SConstants.TOP
0286: && tabPlacement != SConstants.LEFT
0287: && tabPlacement != SConstants.BOTTOM
0288: && tabPlacement != SConstants.RIGHT) {
0289: throw new IllegalArgumentException(
0290: "illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT");
0291: }
0292:
0293: if (this .tabPlacement != tabPlacement) {
0294: this .tabPlacement = tabPlacement;
0295: reload();
0296: }
0297: }
0298:
0299: /**
0300: * Returns the model associated with this tabbedpane.
0301: *
0302: * @see #setModel
0303: */
0304: public SingleSelectionModel getModel() {
0305: return model;
0306: }
0307:
0308: /**
0309: * Sets the model to be used with this tabbedpane.
0310: *
0311: * @param model the model to be used
0312: * @see #getModel
0313: */
0314: public void setModel(SingleSelectionModel model) {
0315: if (this .model != null)
0316: this .model.removeChangeListener(fwdChangeEvents);
0317: this .model = model;
0318: if (this .model != null)
0319: this .model.addChangeListener(fwdChangeEvents);
0320: reload();
0321: reload();
0322: }
0323:
0324: /**
0325: * Returns the currently selected index for this tabbedpane.
0326: * Returns -1 if there is no currently selected tab.
0327: *
0328: * @return the index of the selected tab
0329: * @see #setSelectedIndex
0330: */
0331: public int getSelectedIndex() {
0332: return model.getSelectedIndex();
0333: }
0334:
0335: /**
0336: * Sets the selected index for this tabbedpane.
0337: *
0338: * @see #getSelectedIndex
0339: * @see SingleSelectionModel#setSelectedIndex
0340: */
0341: public void setSelectedIndex(int index) {
0342: model.setSelectedIndex(index);
0343: }
0344:
0345: /**
0346: * Returns the currently selected component for this tabbedpane.
0347: * Returns null if there is no currently selected tab.
0348: *
0349: * @return the component corresponding to the selected tab
0350: * @see #setSelectedComponent
0351: */
0352: public SComponent getSelectedComponent() {
0353: int index = getSelectedIndex();
0354: if (index == -1) {
0355: return null;
0356: }
0357: return ((Page) pages.get(index)).component;
0358: }
0359:
0360: /**
0361: * Sets the selected component for this tabbedpane. This
0362: * will automatically set the selectedIndex to the index
0363: * corresponding to the specified component.
0364: *
0365: * @see #getSelectedComponent
0366: */
0367: public void setSelectedComponent(SComponent c) {
0368: int index = indexOfComponent(c);
0369: if (index != -1) {
0370: setSelectedIndex(index);
0371: } else {
0372: throw new IllegalArgumentException(
0373: "component not found in tabbed pane");
0374: }
0375: }
0376:
0377: /**
0378: * Returns the index of the tab for the specified component.
0379: * Returns -1 if there is no tab for this component.
0380: *
0381: * @param component the component for the tab
0382: */
0383: public int indexOfComponent(SComponent component) {
0384: for (int i = 0; i < getTabCount(); ++i) {
0385: if (((Page) pages.get(i)).component.equals(component)) {
0386: return i;
0387: }
0388: }
0389: return -1;
0390: }
0391:
0392: /**
0393: * Returns the number of tabs in this tabbedpane.
0394: *
0395: * @return an int specifying the number of tabbed pages
0396: */
0397: public int getTabCount() {
0398: return pages.size();
0399: }
0400:
0401: /**
0402: * Inserts a <i>component</i>, at <i>index</i>, represented by a
0403: * <i>title</i> and/or <i>icon</i>, either of which may be null.
0404: * Uses java.util.ArrayList internally, see insertElementAt()
0405: * for details of insertion conventions.
0406: *
0407: * @param title the title to be displayed in this tab
0408: * @param icon the icon to be displayed in this tab
0409: * @param component The component to be displayed when this tab is clicked.
0410: * @param tip the tooltip to be displayed for this tab
0411: * @param index the position to insert this new tab
0412: * @see #addTab
0413: * @see #removeTabAt
0414: */
0415: public void insertTab(String title, SIcon icon,
0416: SComponent component, String tip, int index) {
0417:
0418: SIcon disabledIcon = null;
0419:
0420: if (icon != null && icon instanceof SImageIcon) {
0421: disabledIcon = new SImageIcon(new ImageIcon(
0422: GrayFilter.createDisabledImage(((SImageIcon) icon)
0423: .getImage())));
0424: }
0425:
0426: Page p = new Page(title, icon, disabledIcon, component, tip);
0427: pages.add(index, p);
0428:
0429: contents.addComponent(p.component, p.component.getName());
0430:
0431: if (pages.size() == 1) {
0432: setSelectedIndex(0);
0433: } else if (index <= getSelectedIndex()) {
0434: setSelectedIndex(getSelectedIndex() + 1);
0435: }
0436:
0437: reload();
0438: }
0439:
0440: /**
0441: * Adds a <i>component</i> and <i>tip</i> represented by a <i>title</i>
0442: * and/or <i>icon</i>, either of which can be null.
0443: * Cover method for insertTab().
0444: *
0445: * @param title the title to be displayed in this tab
0446: * @param icon the icon to be displayed in this tab
0447: * @param component The component to be displayed when this tab is clicked.
0448: * @param tip the tooltip to be displayed for this tab
0449: * @see #insertTab
0450: * @see #removeTabAt
0451: */
0452: public void addTab(String title, SIcon icon, SComponent component,
0453: String tip) {
0454: insertTab(title, icon, component, tip, pages.size());
0455: }
0456:
0457: /**
0458: * Adds a <i>component</i> represented by a <i>title</i> and/or <i>icon</i>,
0459: * either of which can be null.
0460: * Cover method for insertTab().
0461: *
0462: * @param title the title to be displayed in this tab
0463: * @param icon the icon to be displayed in this tab
0464: * @param component The component to be displayed when this tab is clicked.
0465: * @see #insertTab
0466: * @see #removeTabAt
0467: */
0468: public void addTab(String title, SIcon icon, SComponent component) {
0469: insertTab(title, icon, component, null, pages.size());
0470: }
0471:
0472: /**
0473: * Adds a <i>component</i> represented by a <i>title</i> and no icon.
0474: * Cover method for insertTab().
0475: *
0476: * @param title the title to be displayed in this tab
0477: * @param component The component to be displayed when this tab is clicked.
0478: * @see #insertTab
0479: * @see #removeTabAt
0480: */
0481: public void addTab(String title, SComponent component) {
0482: insertTab(title, null, component, null, pages.size());
0483: }
0484:
0485: /**
0486: * Adds a <i>component</i> with the specified tab title.
0487: * Cover method for insertTab().
0488: *
0489: * @param title the title to be displayed in this tab
0490: * @param component The component to be displayed when this tab is clicked.
0491: * @see #insertTab
0492: * @see #removeTabAt
0493: */
0494: public SComponent add(String title, SComponent component) {
0495: addTab(title, component);
0496: return component;
0497: }
0498:
0499: /**
0500: * Adds a <i>component</i> at the specified tab index. If constraints
0501: * is a String or an Icon, it will be used for the tab title,
0502: * otherwise the component's name will be used as the tab title.
0503: * Cover method for insertTab().
0504: *
0505: * @param component The component to be displayed when this tab is clicked.
0506: * @param constraints the object to be displayed in the tab
0507: * @see #insertTab
0508: * @see #removeTabAt
0509: */
0510: public SComponent addComponent(SComponent component,
0511: Object constraints) {
0512: return addComponent(component, constraints, pages.size());
0513: }
0514:
0515: /**
0516: * Adds a <i>component</i> at the specified tab index. If constraints
0517: * is a String or an Icon, it will be used for the tab title,
0518: * otherwise the component's name will be used as the tab title.
0519: * Cover method for insertTab().
0520: *
0521: * @param component The component to be displayed when this tab is clicked.
0522: * @param constraints the object to be displayed in the tab
0523: * @param index the position to insert this new tab
0524: * @see #insertTab
0525: * @see #removeTabAt
0526: */
0527: public SComponent addComponent(SComponent component,
0528: Object constraints, int index) {
0529: SIcon icon = constraints instanceof SIcon ? (SIcon) constraints
0530: : null;
0531: String title = constraints instanceof String ? (String) constraints
0532: : null;
0533: insertTab(title, icon, component, null, Math.min(index, pages
0534: .size()));
0535:
0536: return component;
0537: }
0538:
0539: /**
0540: * Removes the tab at <i>index</i>.
0541: * After the component associated with <i>index</i> is removed,
0542: * its visibility is reset to true to ensure it will be visible
0543: * if added to other containers.
0544: *
0545: * @param index the index of the tab to be removed
0546: * @see #addTab
0547: * @see #insertTab
0548: */
0549: public void removeTabAt(int index) {
0550: // If we are removing the currently selected tab AND
0551: // it happens to be the last tab in the bunch, then
0552: // select the previous tab, except it is the last one.
0553: // TODO: how is a tabbedPane with no tabs rendered?
0554: int newTabCount = getTabCount() - 1;
0555: int selected = getSelectedIndex();
0556: removePageAt(index);
0557: if (newTabCount > 0 && selected != -1) {
0558: if (selected >= (newTabCount)) {
0559: /* last tab was selected and maybe removed, so try to find a
0560: * tab to select before
0561: */
0562: int decrement = 1;
0563:
0564: while (newTabCount > decrement
0565: && !isEnabledAt(newTabCount - decrement)) {
0566: decrement++;
0567: }
0568: if (isEnabledAt(newTabCount - decrement)) {
0569: setSelectedIndex(newTabCount - decrement);
0570: } else {
0571: // only disabled tabs left
0572: setSelectedIndex(-1);
0573: }
0574: } else {
0575: int newTab = selected;
0576: /* some tab was selected and maybe removed, so try to find a
0577: * tab to select behind or before the removed one
0578: */
0579: while ((newTabCount - 1 > newTab)
0580: && !isEnabledAt(newTab)) {
0581: newTab++;
0582: }
0583: if (isEnabledAt(newTab)) {
0584: setSelectedIndex(newTab);
0585: getSelectedComponent().setVisible(true);
0586: } else {
0587: // see if there is an enabled tab before
0588: newTab = selected - 1;
0589: if (newTab == -1) {
0590: setSelectedIndex(-1);
0591: return;
0592: }
0593: while (newTab > 0 && !isEnabledAt(newTab)) {
0594: newTab--;
0595: }
0596: if (isEnabledAt(newTab)) {
0597: setSelectedIndex(newTab);
0598: getSelectedComponent().setVisible(true);
0599: } else {
0600: // only disabled tabs left
0601: setSelectedIndex(-1);
0602: }
0603: }
0604:
0605: }
0606: } else {
0607: // no tab left
0608: setSelectedIndex(-1);
0609: }
0610: }
0611:
0612: /**
0613: * Removes the tab which corresponds to the specified component.
0614: *
0615: * @param component the component to remove from the tabbedpane
0616: * @see #addTab
0617: * @see #removeTabAt
0618: */
0619: public void remove(SComponent component) {
0620: int index = indexOfComponent(component);
0621: if (index != -1) {
0622: removeTabAt(index);
0623: }
0624: }
0625:
0626: /**
0627: * Sets the maximum tabs per line. tabs >= 0: No maximum.
0628: */
0629: public void setMaxTabsPerLine(int tabs) {
0630: if (tabs != maxTabsPerLine) {
0631: maxTabsPerLine = tabs;
0632: reload();
0633: }
0634: }
0635:
0636: /**
0637: * Returns the maximum tabs per line.
0638: */
0639: public int getMaxTabsPerLine() {
0640: return maxTabsPerLine;
0641: }
0642:
0643: /**
0644: * Returns the component at <i>index</i>.
0645: *
0646: * @see #setComponentAt
0647: */
0648: public SComponent getComponentAt(int index) {
0649: return ((Page) pages.get(index)).component;
0650: }
0651:
0652: /**
0653: * Returns the tab title at <i>index</i>.
0654: *
0655: * @see #setTitleAt
0656: */
0657: public String getTitleAt(int index) {
0658: return ((Page) pages.get(index)).title;
0659: }
0660:
0661: /**
0662: * Returns the tab icon at <i>index</i>.
0663: *
0664: * @see #setIconAt
0665: */
0666: public SIcon getIconAt(int index) {
0667: return ((Page) pages.get(index)).icon;
0668: }
0669:
0670: /**
0671: * Returns the tab disabled icon at <i>index</i>.
0672: *
0673: * @see #setDisabledIconAt
0674: */
0675: public SIcon getDisabledIconAt(int index) {
0676: return ((Page) pages.get(index)).disabledIcon;
0677: }
0678:
0679: /**
0680: * Returns the tab background color at <i>index</i>.
0681: *
0682: * @see #setBackgroundAt
0683: */
0684: public Color getBackgroundAt(int index) {
0685: return ((Page) pages.get(index)).background;
0686: }
0687:
0688: /**
0689: * Returns the tab foreground color at <i>index</i>.
0690: *
0691: * @see #setForegroundAt
0692: */
0693: public Color getForegroundAt(int index) {
0694: return ((Page) pages.get(index)).foreground;
0695: }
0696:
0697: /**
0698: * Returns the tab style at <i>index</i>.
0699: *
0700: * @see #setStyleAt
0701: */
0702: public String getStyleAt(int index) {
0703: return ((Page) pages.get(index)).style;
0704: }
0705:
0706: /**
0707: * Returns whether or not the tab at <i>index</i> is
0708: * currently enabled.
0709: *
0710: * @see #setEnabledAt
0711: */
0712: public boolean isEnabledAt(int index) {
0713: return ((Page) pages.get(index)).enabled;
0714: }
0715:
0716: /**
0717: * Sets the component at <i>index</i> to <i>component</i> which must not be null.
0718: * An internal exception is raised if there is no tab at that index.
0719: *
0720: * @param index the tab index where the title should be set
0721: * @param component the component for the tab
0722: * @see #getComponentAt
0723: */
0724: public void setComponentAt(int index, SComponent component) {
0725: contents.remove(index);
0726: ((Page) pages.get(index)).component = component;
0727: contents.add(component, component.getName(), index);
0728: component.setVisible(getSelectedIndex() == index);
0729: reload();
0730: }
0731:
0732: /**
0733: * Sets the title at <i>index</i> to <i>title</i> which can be null.
0734: * An internal exception is raised if there is no tab at that index.
0735: *
0736: * @param index the tab index where the title should be set
0737: * @param title the title to be displayed in the tab
0738: * @see #getTitleAt
0739: */
0740: public void setTitleAt(int index, String title) {
0741: Page page = (Page) pages.get(index);
0742: if (isDifferent(page.title, title)) {
0743: page.title = title;
0744: reload();
0745: }
0746: }
0747:
0748: /**
0749: * Sets the icon at <i>index</i> to <i>icon</i> which can be null.
0750: * An internal exception is raised if there is no tab at that index.
0751: *
0752: * @param index the tab index where the icon should be set
0753: * @param icon the icon to be displayed in the tab
0754: * @see #getIconAt
0755: */
0756: public void setIconAt(int index, SIcon icon) {
0757: Page page = (Page) pages.get(index);
0758: if (isDifferent(page.icon, icon)) {
0759: page.icon = icon;
0760: reload();
0761: }
0762: }
0763:
0764: /**
0765: * Sets the disabled icon at <i>index</i> to <i>icon</i> which can be null.
0766: * An internal exception is raised if there is no tab at that index.
0767: *
0768: * @param index the tab index where the disabled icon should be set
0769: * @param disabledIcon the icon to be displayed in the tab when disabled
0770: * @see #getDisabledIconAt
0771: */
0772: public void setDisabledIconAt(int index, SIcon disabledIcon) {
0773: Page page = (Page) pages.get(index);
0774: if (isDifferent(page.disabledIcon, disabledIcon)) {
0775: page.disabledIcon = disabledIcon;
0776: reload();
0777: }
0778: }
0779:
0780: /**
0781: * Sets the background color at <i>index</i> to <i>background</i>
0782: * which can be null, in which case the tab's background color
0783: * will default to the background color of the tabbedpane.
0784: * An internal exception is raised if there is no tab at that index.
0785: *
0786: * @param index the tab index where the background should be set
0787: * @param background the color to be displayed in the tab's background
0788: * @see #getBackgroundAt
0789: */
0790: public void setBackgroundAt(int index, Color background) {
0791: Page page = (Page) pages.get(index);
0792: if (isDifferent(page.background, background)) {
0793: page.background = background;
0794: reload();
0795: }
0796: }
0797:
0798: /**
0799: * Sets the foreground color at <i>index</i> to <i>foreground</i>
0800: * which can be null, in which case the tab's foreground color
0801: * will default to the foreground color of this tabbedpane.
0802: * An internal exception is raised if there is no tab at that index.
0803: *
0804: * @param index the tab index where the foreground should be set
0805: * @param foreground the color to be displayed as the tab's foreground
0806: * @see #getForegroundAt
0807: */
0808: public void setForegroundAt(int index, Color foreground) {
0809: Page page = (Page) pages.get(index);
0810: if (isDifferent(page.foreground, foreground)) {
0811: page.foreground = foreground;
0812: reload();
0813: }
0814: }
0815:
0816: /**
0817: * Sets the style at <i>index</i> to <i>style</i>
0818: * which can be null, in which case the tab's style
0819: * will default to the style of this tabbedpane.
0820: * An internal exception is raised if there is no tab at that index.
0821: *
0822: * @param index the tab index where the style should be set
0823: * @param style the style to be used as the tab's style
0824: * @see #getStyleAt
0825: */
0826: public void setStyleAt(int index, String style) {
0827: Page page = (Page) pages.get(index);
0828: if (page.style != style) {
0829: page.style = style;
0830: reload();
0831: }
0832: }
0833:
0834: /**
0835: * Sets whether or not the tab at <i>index</i> is enabled.
0836: * An internal exception is raised if there is no tab at that index.
0837: *
0838: * @param index the tab index which should be enabled/disabled
0839: * @param enabled whether or not the tab should be enabled
0840: * @see #isEnabledAt
0841: */
0842: public void setEnabledAt(int index, boolean enabled) {
0843: Page page = (Page) pages.get(index);
0844: if (page.enabled != enabled) {
0845: page.enabled = enabled;
0846: reload();
0847: }
0848: }
0849:
0850: /**
0851: * Set the tooltip text for tab at <i>index</i>
0852: *
0853: * @param index set the tooltip for this tab
0854: */
0855: public void setToolTipTextAt(int index, String toolTip) {
0856: Page page = (Page) pages.get(index);
0857: if (isDifferent(page.toolTip, toolTip)) {
0858: page.toolTip = toolTip;
0859: reload();
0860: }
0861: }
0862:
0863: /**
0864: * Get the tooltip text from tab at <i>index</i>
0865: *
0866: * @return the text or <i>null</i> if not set.
0867: */
0868: public String getToolTipTextAt(int index) {
0869: return ((Page) pages.get(index)).toolTip;
0870: }
0871:
0872: /**
0873: * Sets the component at <i>index</i> to <i>component</i>.
0874: * An internal exception is raised if there is no tab at that index.
0875: *
0876: * @param index the tab index where this component is being placed
0877: * @param component the component for the tab
0878: * @see #getComponent(int)
0879: */
0880: public void setComponent(int index, SComponent component) {
0881: Page page = (Page) pages.get(index);
0882: if (component != page.component) {
0883: if (page.component != null) {
0884: contents.remove(page.component);
0885: }
0886: page.component = component;
0887: contents.addComponent(page.component, page.component
0888: .getName());
0889: if (getSelectedIndex() == index)
0890: card.show(component);
0891:
0892: reload();
0893: }
0894: }
0895:
0896: /**
0897: * Returns the first tab index with a given <i>title</i>,
0898: * Returns -1 if no tab has this title.
0899: *
0900: * @param title the title for the tab
0901: */
0902: public int indexOfTab(String title) {
0903: for (int i = 0; i < getTabCount(); i++) {
0904: String titleAt = getTitleAt(i);
0905: if (title == null && titleAt == null || title != null
0906: && title.equals(titleAt))
0907: return i;
0908: }
0909: return -1;
0910: }
0911:
0912: /**
0913: * Returns the first tab index with a given <i>icon</i>.
0914: * Returns -1 if no tab has this icon.
0915: *
0916: * @param icon the icon for the tab
0917: */
0918: public int indexOfTab(SIcon icon) {
0919: for (int i = 0; i < getTabCount(); i++) {
0920: SIcon iconAt = getIconAt(i);
0921: if (icon == null && iconAt == null || icon != null
0922: && icon.equals(iconAt))
0923: return i;
0924: }
0925: return -1;
0926: }
0927:
0928: private void removePageAt(int i) {
0929: contents.remove(((Page) pages.get(i)).component);
0930: pages.remove(i);
0931: reload();
0932: }
0933:
0934: /**
0935: * Lightweight container for tab properties.
0936: */
0937: private static class Page implements Serializable {
0938: public String title;
0939: public String toolTip;
0940: public Color foreground;
0941: public Color background;
0942: public SIcon icon;
0943: public SIcon disabledIcon;
0944: public boolean enabled = true;
0945: public String style;
0946: public SComponent component;
0947:
0948: public Page(String title, SIcon icon, SIcon disabledIcon,
0949: SComponent component, String tip) {
0950: this .title = title;
0951: this .toolTip = tip;
0952: this .icon = icon;
0953: this .disabledIcon = disabledIcon;
0954: this .component = component;
0955: }
0956: }
0957:
0958: /**
0959: * Set the parent frame of this tabbed pane
0960: *
0961: * @param f the parent frame.
0962: */
0963: public void setParentFrame(SFrame f) {
0964: super .setParentFrame(f);
0965: contents.setParentFrame(f);
0966: }
0967:
0968: public void setCG(TabbedPaneCG cg) {
0969: super .setCG(cg);
0970: }
0971:
0972: /**
0973: * Tab was clicked.
0974: *
0975: * @see LowLevelEventListener#processLowLevelEvent(String, String[])
0976: */
0977: public void processLowLevelEvent(String action, String[] values) {
0978: processKeyEvents(values);
0979: if (action.endsWith("_keystroke"))
0980: return;
0981:
0982: for (int i = 0; i < values.length; ++i) {
0983: try {
0984: int index = new Integer(values[i]).intValue();
0985: if (index < 0 || index >= pages.size())
0986: continue;
0987:
0988: /* prevent clever users from showing
0989: * disabled tabs
0990: */
0991: if (((Page) pages.get(index)).enabled) {
0992: lleChangedIndex = index;
0993: SForm.addArmedComponent(this );
0994: return;
0995: }
0996: } catch (NumberFormatException nfe) {
0997: continue;
0998: }
0999: }
1000: }
1001:
1002: /**
1003: * Does nothin'.
1004: */
1005: public void fireIntermediateEvents() {
1006: requestFocus();
1007: }
1008:
1009: /**
1010: * Sets selection and fire changeevents, if user changed
1011: * tab selection.
1012: */
1013: public void fireFinalEvents() {
1014: super .fireFinalEvents();
1015: if (lleChangedIndex > -1)
1016: setSelectedIndex(lleChangedIndex);
1017: lleChangedIndex = -1;
1018: }
1019:
1020: /**
1021: * @see LowLevelEventListener#isEpochCheckEnabled()
1022: */
1023: public boolean isEpochCheckEnabled() {
1024: return epochCheckEnabled;
1025: }
1026:
1027: /**
1028: * @see LowLevelEventListener#isEpochCheckEnabled()
1029: */
1030: public void setEpochCheckEnabled(boolean epochCheckEnabled) {
1031: this .epochCheckEnabled = epochCheckEnabled;
1032: }
1033:
1034: public void removeAllTabs() {
1035: while (getTabCount() != 0) {
1036: removeTabAt(0);
1037: }
1038: }
1039:
1040: }
|