TabbedPane.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:21k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit;
  26. import com.sun.lwuit.animations.Transition;
  27. import com.sun.lwuit.events.SelectionListener;
  28. import com.sun.lwuit.geom.Dimension;
  29. import com.sun.lwuit.geom.Rectangle;
  30. import com.sun.lwuit.layouts.BorderLayout;
  31. import com.sun.lwuit.list.DefaultListModel;
  32. import com.sun.lwuit.list.ListCellRenderer;
  33. import com.sun.lwuit.plaf.Style;
  34. import com.sun.lwuit.plaf.UIManager;
  35. import java.util.Enumeration;
  36. import java.util.Hashtable;
  37. import java.util.Vector;
  38. /**
  39.  * A component that lets the user switch between a group of components by
  40.  * clicking on a tab with a given title and/or icon.
  41.  * 
  42.  * <p>
  43.  * Tabs/components are added to a <code>TabbedPane</code> object by using the
  44.  * <code>addTab</code> and <code>insertTab</code> methods.
  45.  * A tab is represented by an index corresponding
  46.  * to the position it was added in, where the first tab has an index equal to 0
  47.  * and the last tab has an index equal to the tab count minus 1.
  48.  * <p>
  49.  * The <code>TabbedPane</code> uses a <code>SingleSelectionModel</code>
  50.  * to represent the set of tab indices and the currently selected index.  
  51.  * If the tab count is greater than 0, then there will always be a selected 
  52.  * index, which by default will be initialized to the first tab.  
  53.  * If the tab count is 0, then the selected index will be -1.
  54.  * <p>
  55.  * 
  56.  * @author Tamir Shabat
  57.  *
  58.  */
  59. public class TabbedPane extends Container {
  60.     private Transition transitionRight;
  61.     private Transition transitionLeft;
  62.     private Container contentPane = new Container(new BorderLayout());
  63.     private List tabsList = new List();
  64.     private Hashtable tabsTable = new Hashtable();
  65.     /** 
  66.      * Where the tabs are placed.
  67.      */
  68.     private int tabPlacement = -1;
  69.     /**
  70.      * The TabbedPane surrounded border width (contentPane and tabs border)
  71.      */
  72.     private int tPBorder = 1;
  73.     /**
  74.      * Creates an empty <code>TabbedPane</code> with a default
  75.      * tab placement of <code>Component.TOP</code>.
  76.      */
  77.     public TabbedPane() {
  78.         this(TOP);
  79.     }
  80.     /**
  81.      * Creates an empty <code>TabbedPane</code> with the specified tab placement
  82.      * of either: <code>Component.TOP</code>, <code>Component.BOTTOM</code>,
  83.      * <code>Component.LEFT</code>, or <code>Component.RIGHT</code>.
  84.      *
  85.      * @param tabPlacement the placement for the tabs relative to the content
  86.      */
  87.     public TabbedPane(int tabPlacement) {
  88.         super(new BorderLayout());
  89.         contentPane.setUIID("TabbedPane");
  90.         contentPane.getStyle().setBgPainter(new Painter() {
  91.             public void paint(Graphics g, Rectangle rect) {
  92.                 UIManager.getInstance().getLookAndFeel().
  93.                         drawTabbedPaneContentPane(TabbedPane.this, g, rect,
  94.                         tabsList.getPreferredSize(), tabsList.size(),
  95.                         tabsList.getSelectedIndex(), tabsList.getElementSize(true, true),
  96.                         tabsList.getScrollX(), tabsList.getScrollY());
  97.             }
  98.         });
  99.         super.addComponent(BorderLayout.CENTER, contentPane);
  100.         
  101.         setTabPlacement(tabPlacement);
  102.         tabsList.getUnselectedStyle().setPadding(0, 0, 0, 0);
  103.         tabsList.getUnselectedStyle().setMargin(0, 0, 0, 0);
  104.         tabsList.getUnselectedStyle().setBorder(null);
  105.         tabsList.getSelectedStyle().setPadding(0, 0, 0, 0);
  106.         tabsList.getSelectedStyle().setMargin(0, 0, 0, 0);
  107.         tabsList.getSelectedStyle().setBorder(null);
  108.         
  109.         tabsList.setListCellRenderer(new TabsRenderer());
  110.         tabsList.setItemGap(0);
  111.         tabsList.setIsScrollVisible(false);
  112.         tabsList.setSmoothScrolling(false);
  113.         tabsList.setBorderGap(0);        
  114.         tabsList.addSelectionListener(new SelectionListener() {
  115.             public void selectionChanged(int oldSelected, int newSelected) {
  116.                 Component c = (Component) tabsList.getModel().getItemAt(newSelected);
  117.                 Transition t = transitionLeft;
  118.                 if(oldSelected < newSelected) {
  119.                     t = transitionRight;
  120.                 }
  121.                 if(c != null) {
  122.                     if(t == null || contentPane.getComponentCount() == 0) {
  123.                         contentPane.removeAll();
  124.                         contentPane.addComponent(BorderLayout.CENTER, (Component) tabsTable.get(c));
  125.                         if(isInitialized()) {
  126.                             revalidate();
  127.                         } else {
  128.                             setShouldCalcPreferredSize(true);
  129.                         }
  130.                     } else {
  131.                         contentPane.flushReplace();
  132.                         contentPane.replace(contentPane.getComponentAt(0), (Component) tabsTable.get(c), t);
  133.                     }
  134.                 }
  135.             }
  136.         });        
  137.         
  138.     }
  139.     
  140.     /**
  141.      * Indicates the transition to use when switching between tabs from right to left. 
  142.      * 
  143.      * @param transitionLeft transition to use when switching tabs or null to avoid transition
  144.      */
  145.     public void setTransitionLeft(Transition transitionLeft) {
  146.         this.transitionLeft = transitionLeft;
  147.     }
  148.     /**
  149.      * Indicates the transition to use when switching between tabs from right to left. 
  150.      * 
  151.      * @return the transition towards the left direction
  152.      */
  153.     public Transition getTransitionLeft() {
  154.         return transitionLeft;
  155.     }
  156.     
  157.     /**
  158.      * Indicates the transition to use when switching between tabs from left to right. 
  159.      * 
  160.      * @param transitionRight transition to use when switching tabs or null to avoid transition
  161.      */
  162.     public void setTransitionRight(Transition transitionRight) {
  163.         this.transitionRight = transitionRight;
  164.     }
  165.     /**
  166.      * Indicates the transition to use when switching between tabs from left to right. 
  167.      * 
  168.      * @return the transition towards the right direction
  169.      */
  170.     public Transition getTransitionRight() {
  171.         return transitionRight;
  172.     }
  173.     
  174.     /**
  175.      * @inheritDoc
  176.      */
  177.     public void setFocusable(boolean b) {
  178.         if(tabsList != null) {
  179.             tabsList.setFocusable(b);
  180.         }
  181.         super.setFocusable(b);
  182.     }
  183.     
  184.     /**
  185.      * This method adds a listener to the tabs.
  186.      * 
  187.      * @param listener a selection listener to gets the selection
  188.      * events
  189.      */
  190.     public void addTabsListener(SelectionListener listener){
  191.         tabsList.addSelectionListener(listener);
  192.     }
  193.     
  194.     /**
  195.      * @inheritDoc
  196.      */
  197.     public void requestFocus() {
  198.         tabsList.requestFocus();
  199.     }
  200.     
  201.     /**
  202.      * @inheritDoc
  203.      */
  204.     protected Dimension calcPreferredSize() {
  205.         int maxContentW = 0;
  206.         int maxContentH = 0;
  207.         int maxW = 0;
  208.         int maxH = 0;
  209.         for (int i = 0; i < tabsList.size(); i++) {
  210.             Component tabsComp = (Component) tabsList.getModel().getItemAt(i);
  211.             Component contentComp = (Component) tabsTable.get(tabsComp);
  212.             if (contentComp.getPreferredW() > maxContentW) {
  213.                 maxContentW = contentComp.getPreferredW();
  214.             }
  215.             if (contentComp.getPreferredH() > maxContentH) {
  216.                 maxContentH = contentComp.getPreferredH();
  217.             }
  218.         }
  219.         if (tabPlacement == TOP || tabPlacement == BOTTOM) {
  220.             maxW = maxContentW;
  221.             maxH = tabsList.getPreferredH() + maxContentH;
  222.         } else {
  223.             maxW = tabsList.getPreferredW() + maxContentW;
  224.             maxH = maxContentH;
  225.         }
  226.         return new Dimension(maxW, maxH);
  227.     }
  228.     /**
  229.      * Sets the tab placement for this tabbedpane.
  230.      * Possible values are:<ul>
  231.      * <li><code>Component.TOP</code>
  232.      * <li><code>Component.BOTTOM</code>
  233.      * <li><code>Component.LEFT</code>
  234.      * <li><code>Component.RIGHT</code>
  235.      * </ul>
  236.      * The default value, if not set, is <code>Component.TOP</code>.
  237.      * 
  238.      * @param tabPlacement the placement for the tabs relative to the content
  239.      */
  240.     public void setTabPlacement(int tabPlacement) {
  241.         if (tabPlacement != TOP && tabPlacement != LEFT &&
  242.                 tabPlacement != BOTTOM && tabPlacement != RIGHT) {
  243.             throw new IllegalArgumentException("illegal tab placement: must be TOP, BOTTOM, LEFT, or RIGHT");
  244.         }
  245.         if (this.tabPlacement == tabPlacement) {
  246.             return;
  247.         }
  248.         this.tabPlacement = tabPlacement;
  249.         removeComponent(tabsList);
  250.         
  251.         if (tabPlacement == TOP || tabPlacement == BOTTOM) {
  252.             tabsList.setOrientation(List.HORIZONTAL);
  253.             if (tabPlacement == TOP) {
  254.                 super.addComponent(BorderLayout.NORTH, tabsList);
  255.             } else if (tabPlacement == BOTTOM) {
  256.                 super.addComponent(BorderLayout.SOUTH, tabsList);
  257.             }
  258.         } else {// LEFT Or RIGHT
  259.             tabsList.setOrientation(List.VERTICAL);
  260.             if (tabPlacement == LEFT) {
  261.                 super.addComponent(BorderLayout.WEST, tabsList);
  262.             } else {// RIGHT
  263.                 super.addComponent(BorderLayout.EAST, tabsList);
  264.             }
  265.         }
  266.         tabsList.setShouldCalcPreferredSize(true);
  267.         contentPane.setShouldCalcPreferredSize(true);
  268.         revalidate();
  269.     }
  270.     /**
  271.      * Adds a <code>component</code> 
  272.      * represented by a <code>title</code> and/or <code>icon</code>,
  273.      * either of which can be <code>null</code>.
  274.      * Cover method for <code>insertTab</code>.
  275.      * 
  276.      * @param title the title to be displayed in this tab
  277.      * @param icon the icon to be displayed in this tab
  278.      * @param component the component to be displayed when this tab is clicked
  279.      * 
  280.      * @see #insertTab
  281.      * @see #removeTabAt
  282.      */
  283.     public void addTab(String title, Image icon, Component component) {
  284.         insertTab(title, icon, component, tabsList.size());
  285.     }
  286.     /**
  287.      * Adds a <code>component</code> 
  288.      * represented by a <code>title</code> and no <code>icon</code>.
  289.      * Cover method for <code>insertTab</code>.
  290.      * 
  291.      * @param title the title to be displayed in this tab
  292.      * @param component the component to be displayed when this tab is clicked
  293.      * 
  294.      * @see #insertTab
  295.      * @see #removeTabAt
  296.      */
  297.     public void addTab(String title, Component component) {
  298.         insertTab(title, null, component, tabsList.size());
  299.     }
  300.     /**
  301.      * Inserts a <code>component</code>, at <code>index</code>,
  302.      * represented by a <code>title</code> and/or <code>icon</code>,
  303.      * either of which may be <code>null</code>.
  304.      * Uses java.util.Vector internally, see <code>insertElementAt</code>
  305.      * for details of insertion conventions. 
  306.      *
  307.      * @param title the title to be displayed in this tab
  308.      * @param icon the icon to be displayed in this tab
  309.      * @param component The component to be displayed when this tab is clicked.
  310.      * @param index the position to insert this new tab 
  311.      *
  312.      * @see #addTab
  313.      * @see #removeTabAt
  314.      */
  315.     public void insertTab(String title, Image icon, Component component,
  316.             int index) {
  317.         checkIndex(index);
  318.         if (component == null) {
  319.             return;
  320.         }
  321.         Button b = new Button(title != null ? title : "", icon);
  322.         ((DefaultListModel) tabsList.getModel()).addItemAtIndex(b, index);
  323.         tabsTable.put(b, component);
  324.         if (tabsList.size() == 1) {
  325.             contentPane.addComponent(BorderLayout.CENTER, component);
  326.         }
  327.     }
  328.     
  329.     /**
  330.      * Updates the information about the tab details
  331.      * 
  332.      * @param title the title to be displayed in this tab
  333.      * @param icon the icon to be displayed in this tab
  334.      * @param index the position to insert this new tab 
  335.      */
  336.     public void setTabTitle(String title, Image icon, int index) {
  337.         checkIndex(index);
  338.         Button b = (Button)tabsList.getModel().getItemAt(index);
  339.         b.setText(title);
  340.         b.setIcon(icon);
  341.         ((DefaultListModel) tabsList.getModel()).setItem(index, b);
  342.     }
  343.     
  344.     /**
  345.      * Removes the tab at <code>index</code>.
  346.      * After the component associated with <code>index</code> is removed,
  347.      * its visibility is reset to true to ensure it will be visible
  348.      * if added to other containers.
  349.      * @param index the index of the tab to be removed
  350.      * @exception IndexOutOfBoundsException if index is out of range 
  351.      *            (index < 0 || index >= tab count)
  352.      *
  353.      * @see #addTab
  354.      * @see #insertTab  
  355.      */
  356.     public void removeTabAt(int index) {
  357.         checkIndex(index);
  358.         Object key = tabsList.getModel().getItemAt(index);
  359.         ((DefaultListModel) tabsList.getModel()).removeItem(index);
  360.         tabsTable.remove(key);
  361.     }
  362.     /**
  363.      * Returns the tab at <code>index</code>.
  364.      * 
  365.      * @param index the index of the tab to be removed
  366.      * @exception IndexOutOfBoundsException if index is out of range 
  367.      *            (index < 0 || index >= tab count)
  368.      * @return the component at the given tab location
  369.      * @see #addTab
  370.      * @see #insertTab  
  371.      */
  372.     public Component getTabComponentAt(int index) {
  373.         checkIndex(index);
  374.         return (Component) tabsTable.get(((Component) tabsList.getModel().getItemAt(index)));
  375.     }
  376.     
  377.     private void checkIndex(int index) {
  378.         if (index < 0 || index > tabsList.size()) {
  379.             throw new IndexOutOfBoundsException("Index: " + index);
  380.         }
  381.     }
  382.     /**
  383.      * Returns the index of the tab for the specified component.
  384.      * Returns -1 if there is no tab for this component.
  385.      *
  386.      * @param component the component for the tab
  387.      * @return the first tab which matches this component, or -1
  388.      * if there is no tab for this component
  389.      */
  390.     public int indexOfComponent(Component component) {
  391.         for (int i = 0; i < getTabCount(); i++) {
  392.             Component c = (Component) tabsList.getModel().getItemAt(i);
  393.             Component content = (Component) tabsTable.get(c);
  394.                 
  395.             if(component.equals(content)){
  396.                 return i;
  397.             }
  398.         }
  399.         return -1;
  400.     }
  401.     /**
  402.      * Returns the number of tabs in this <code>tabbedpane</code>.
  403.      *
  404.      * @return an integer specifying the number of tabbed pages
  405.      */
  406.     public int getTabCount() {
  407.         return tabsList.size();
  408.     }
  409.     /**
  410.      * Returns the currently selected index for this tabbedpane.
  411.      * Returns -1 if there is no currently selected tab.
  412.      *
  413.      * @return the index of the selected tab
  414.      */
  415.     public int getSelectedIndex() {
  416.         return tabsList.getSelectedIndex();
  417.     }
  418.     /**
  419.      * The prototype is optionally used in calculating the size of an individual
  420.      * tab and is recommended for performance reasons. You should invoke it with a String
  421.      * representing the width/height which will be used to calculate
  422.      * the size required for each element in the list.
  423.      * <p>This operation is not essential and if it isn't invoked the size of the first
  424.      * few tabs is used to determine the overall size of a tab.
  425.      * <p>This allows the size calculations to work across look and feels and allows
  426.      * developers to predetermin size for the tabs. 
  427.      * <p>e.g. For tabs which you would like to always be 5 characters wide
  428.      * you can use a prototype "XXXXX" which would use the preferred size of the XXXXX 
  429.      * String to determine the size of the tabs..
  430.      * 
  431.      * @param title a string to determine the size.
  432.      */
  433.     public void setTabTitlePrototype(String title) {
  434.         tabsList.setRenderingPrototype(title);
  435.     }
  436.     
  437.     /**
  438.      * @inheritDoc
  439.      */
  440.     public String toString() {
  441.         String className = getClass().getName();
  442.         className = className.substring(className.lastIndexOf('.') + 1);
  443.         return className + "[x=" + getX() + " y=" + getY() + " width=" +
  444.                 getWidth() + " height=" + getHeight() + ", tab placement = " +
  445.                 tabPlacement + ", tab count = " + getTabCount() +
  446.                 ", selected index = " + getSelectedIndex() + "]";
  447.     }
  448.     /**
  449.      * @inheritDoc
  450.      */
  451.     public void paint(Graphics g) {
  452.         super.paint(g);
  453.         UIManager.getInstance().getLookAndFeel().drawTabbedPane(g, this);
  454.     }
  455.     /**
  456.      * Sets the tabs selected style
  457.      * @param style
  458.      */
  459.     public void setTabsSelectedStyle(Style style) {
  460.         tabsList.setSelectedStyle(style);
  461.     }
  462.     /**
  463.      * Sets the tabs un selected style
  464.      * @param style
  465.      */
  466.     public void setTabsUnselectedStyle(Style unselectedStyle) {
  467.         tabsList.setUnselectedStyle(unselectedStyle);
  468.     }
  469.     
  470.     /**
  471.      * Sets the content pane selected style
  472.      * @param style
  473.      */
  474.     public void setContentPaneSelectedStyle(Style style) {
  475.         contentPane.setSelectedStyle(style);
  476.     }
  477.     /**
  478.      * Sets the content pane un selected style
  479.      * @param style
  480.      */
  481.     public void setContentPaneUnselectedStyle(Style unselectedStyle) {
  482.         contentPane.setUnselectedStyle(unselectedStyle);
  483.     }
  484.     
  485.     /**
  486.      * @inheritDoc
  487.      */
  488.     public void refreshTheme() {
  489.         Painter p = contentPane.getStyle().getBgPainter();
  490.         super.refreshTheme();
  491.         contentPane.getStyle().setBgPainter(p);
  492.         Enumeration e = tabsTable.elements();
  493.         while(e.hasMoreElements()) {
  494.             Component c = (Component)e.nextElement();
  495.             c.refreshTheme();
  496.         }
  497.     }
  498.     
  499.     /**
  500.      * Returns the placement of the tabs for this tabbedpane.
  501.      * 
  502.      * @return the tab placement value
  503.      * @see #setTabPlacement
  504.      */
  505.     public int getTabPlacement() {
  506.         return tabPlacement;
  507.     }
  508.     /**
  509.      * The TabbedPane surrounded border width
  510.      * 
  511.      * @return The TabbedPane surrounded border width
  512.      */
  513.     public int getTabbedPaneBorderWidth() {
  514.         return tPBorder;
  515.     }
  516.     /**
  517.      * Setting the TabbedPane surrounded border width
  518.      * 
  519.      * @param tabbedPaneBorderWidth TabbedPane surrounded border width
  520.      */
  521.     public void setTabbedPaneBorderWidth(int tabbedPaneBorderWidth) {
  522.         this.tPBorder = tabbedPaneBorderWidth;
  523.     }
  524.     /**
  525.      * @inheritDoc
  526.      */
  527.     public void setPadding(int top, int bottom, int left, int right) {
  528.         if (contentPane != null) {
  529.             contentPane.getStyle().setPadding(top, bottom, left, right);
  530.         }
  531.     }
  532.     
  533.     /**
  534.      * @inheritDoc
  535.      */
  536.     public void setPadding(int orientation, int gap) {
  537.         if (contentPane != null) {
  538.             contentPane.getStyle().setPadding(orientation, gap);
  539.         }
  540.     }
  541.     
  542.     /**
  543.      * Sets the selected index for this tabbedpane. The index must be a valid 
  544.      * tab index.
  545.      * @param index the index to be selected
  546.      * @throws IndexOutOfBoundsException if index is out of range 
  547.      * (index < 0 || index >= tab count)
  548.      */
  549.     public void setSelectedIndex(int index) {
  550.         if (index < 0 || index >= tabsList.size()) {
  551.             throw new IndexOutOfBoundsException("Index: "+index+", Tab count: "+tabsList.size());
  552.         }
  553.         tabsList.setSelectedIndex(index);
  554.     }
  555.     
  556.     class TabsRenderer implements ListCellRenderer {
  557.         public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {            
  558.             // prototype value can cause this
  559.             if(value == null || (!(value instanceof Button))) {
  560.                 value = new Button("" + value);
  561.             }
  562.             return UIManager.getInstance().getLookAndFeel().getTabbedPaneCell(
  563.                     TabbedPane.this, ((Button) value).getText(),
  564.                     ((Button) value).getIcon(), isSelected,
  565.                     list.hasFocus(), list.getStyle(), list.getSelectedStyle(), TabbedPane.this.getStyle(),
  566.                     list.getScrollX(), list.getScrollY(),
  567.                     list.getPreferredSize(), contentPane.getBounds().getSize());
  568.         }
  569.         public Component getListFocusComponent(List list) {
  570.             return null;
  571.         }
  572.     }
  573. }