Package DisplayProject.controls

Source Code of DisplayProject.controls.TabFolder

package DisplayProject.controls;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import org.apache.log4j.Logger;

import DisplayProject.Array_Of_Panel;
import DisplayProject.CompoundField;
import DisplayProject.Constants;
import DisplayProject.GridField;
import DisplayProject.LayoutManagerHelper;
import DisplayProject.TabInfo;
import DisplayProject.actions.Caption;
import DisplayProject.actions.FrameWeight;
import DisplayProject.actions.WidgetState;
import DisplayProject.events.ClientEventManager;
import DisplayProject.plaf.TabFolderUI;
import Framework.EventManager;
import Framework.ForteKeyboardFocusManager;
import Framework.ParameterHolder;
import Framework.TextData;
/**
* The TabFolder class defines a tab folder, a compound widget that displays an array of panels as tabbed pages.
* @since 22/3/08
*
*/
@SuppressWarnings("serial")
public class TabFolder extends JTabbedPane implements FocusListener, CompoundField{
  private static Logger _log = Logger.getLogger(TabFolder.class);
  protected int previousTabIndex = -1;
    protected volatile boolean ignoreChange = false;
   
    private static final String uiClassID = "TabFolderUI";
    /**
     * if set to true the tab folder will not change to a new tab either by
     * user action or by programatic change
     */
    protected volatile boolean preventChange = false;

  public TabFolder() {
    super();
    this.setupControl();
  }

  public TabFolder(int tabPlacement, int tabLayoutPolicy) {
    super(tabPlacement, tabLayoutPolicy);
    this.setupControl();
  }

  public TabFolder(int tabPlacement) {
    super(tabPlacement);
    this.setupControl();
  }
 
  private void setupControl() {
    this.putClientProperty("qq_hidden_pages", new Hashtable<Object, Object>());
    this.addFocusListener(this); // CraigM:21/08/2008 - Moved from unnecessary TabbedPaneModel
    // TF:15/12/2009:DET-141:Set this up to allow inheriting of popup menu
    this.setInheritsPopupMenu(true);
  }

  @Override
  public void doLayout() {
   
    // This overload is to ensure that tab folder resize to the minimum
    // size when the size policy is set to natural

    // TF:30/11/07:Added the layout debug stuff here
    LayoutManagerHelper.setDebugBackgroundColor(this);
    LayoutManagerHelper.makeDebugTooltip(this);

    // TF:13/8/07: A tab folder should always be big enough to
    // contain all it's children, irrespective of size policy
    // Now, the tab folder layout manager built into Swing computes
    // the size needed to fully house the Panels on all
    // the tabs, we need only to reset the minimum size to enforce
    // the correct size
    Dimension d = getSize();
    setMinimumSize(null);
    Dimension minSize = getMinimumSize();

    int newWidth = this.getWidth();
    int newHeight = this.getHeight();
    int polW = GridField.getConstraints(this).getWidthPolicy();
    int polH = GridField.getConstraints(this).getHeightPolicy();

    /*
     * get the border sizes
     */
    Insets pad = this.getInsets();

    /*
     * calculate new width as needed
     */
    int desiredWidth = pad.left + minSize.width + pad.right;
    if (desiredWidth > newWidth || polW == Constants.SP_NATURAL) {
      newWidth = desiredWidth;
    }
    // If we've got an explicit size set, maintain that as the lower
    // bound
    // TF: If we have tab folder in forte which has an explicit size
    // set, but this is
    // too small to contain it's children, Forte would expand this
    // up. We currently just
    // always obey the minimum size. Logged as JIRA ITC-5
    if (polW == Constants.SP_EXPLICIT) {
      // if (newWidth < d.width) {
      newWidth = d.width;
      // }
    }

    /*
     * calculate new height as needed
     */
    int desiredHeight = pad.top + minSize.height + pad.bottom;
    if (desiredHeight > newHeight || polH == Constants.SP_NATURAL) {
      newHeight = desiredHeight;
    }
    // If we've got an explicit size set, maintain that as the lower
    // bound
    // TF: If we have tab folder in forte which has an explicit size
    // set, but this is
    // too small to contain it's children, Forte would expand this
    // up. We currently just
    // always obey the minimum size.
    if (polH == Constants.SP_EXPLICIT) {
      // if (newHeight < d.height + pad.top + pad.bottom) {
      // newHeight = d.height + pad.top + pad.bottom;
      // }
      newHeight = d.height;
    }
    Dimension newDim = new Dimension(newWidth, newHeight);
    if (!(newDim.equals(this.getSize()))) {
      this.setMinimumSize(newDim);
      this.setPreferredSize(newDim);
      this.setBounds(this.getX(), this.getY(), newWidth,
          newHeight);
      getParent().invalidate();
      getParent().validate();
    }
    super.doLayout();
  }
//PM:24/4/08 removed to help debugging
//  @Override
//  public String toString() {
//    return "TabFolder [" + this.getName() + "]";
//  }
//PM:25/4/08 not sure this is neaded anymore
//  @Override
//  public void addTab(String title, Component component) {
//    /*******************************************************************
//     * TF:15/8/07:Panels displayed in tabs hide the bottom 2 pixels
//     * (highlighting) of the tab. Hence, to work around this we'll
//     * render the tab object as non-opaque This has a side effect of not
//     * allowing pages of a tab folder to have their own background
//     * colour.
//     ******************************************************************/
//    if (component instanceof JComponent) {
//      ((JComponent) component).setOpaque(false);
//    }
//    super.addTab(title, component);
//  }
//
//  @Override
//  public void addTab(String title, Icon icon, Component component) {
//    if (component instanceof JComponent) {
//      ((JComponent) component).setOpaque(false);
//    }
//    super.addTab(title, icon, component);
//  }
//
//  @Override
//  public void addTab(String title, Icon icon, Component component,
//      String tip) {
//    if (component instanceof JComponent) {
//      ((JComponent) component).setOpaque(false);
//    }
//    super.addTab(title, icon, component, tip);
//  }

  @Override
  public Dimension getMinimumSize() {
    if (!isMinimumSizeSet()) {
      Dimension d = super.getMinimumSize();
      int width = this.getWidth();
      int height = this.getHeight();
      int polW = GridField.getConstraints(this).getWidthPolicy();
      int polH = GridField.getConstraints(this).getHeightPolicy();

      /*
       * get the border sizes
       */
      Insets pad = this.getInsets();

      // If we've got an explicit size set, maintain that as the
      // lower bound
      if (polH == Constants.SP_EXPLICIT
          && pad.top + pad.bottom + height > d.height) {
        d.height = height + pad.top + pad.bottom;
      }

      // If we've got an explicit size set, maintain that as the
      // lower bound
      if (polW == Constants.SP_EXPLICIT
          && pad.left + pad.right + width > d.width) {
        d.width = width + pad.left + pad.right;
      }
      return d;
    } else {
      return super.getMinimumSize();
    }
  }

  @Override
  public void remove(Component component) {
    // PM:29/11/07 remove all tabs
    List<JPanel> pages = getAllPages();
    pages.remove(component);
    super.remove(component);
  }

  private static final String PARENT_TAB_FOLDER_PROPERTY = "qq_Tab_Parent";
  private static final String IS_TAB_VISIBLE_PROPERTY = "qq_Tab_visible";
  private static final String TAB_INFO_PROPERTY = "qq_tabInfo";
  private static final String ALL_PAGES_PROPERTY = "qq_all_pages";
 
 
  @Override
  public void insertTab(String title, Icon icon, Component component,
      String tip, int index) {
   
    ((JPanel)component).putClientProperty(PARENT_TAB_FOLDER_PROPERTY, this)
    // PM:29/11/07 store all tabs
    if (WidgetState.get((JPanel)component) != Constants.FS_INVISIBLE) {//PM:14/01/2009: Only add the page if it is visible
      ((JPanel)component).putClientProperty(IS_TAB_VISIBLE_PROPERTY, true);
      super.insertTab(title, icon, component, tip, getTabCount());
    } else {//PM:14/01/2009:Otherwise add the page to the hidden pages list
            ((JPanel)component).putClientProperty(IS_TAB_VISIBLE_PROPERTY, false);
      TabInfo ti = (TabInfo)((JComponent)component).getClientProperty(TAB_INFO_PROPERTY);
            if (ti == null) {
              ti = new TabInfo(title, null, index, (JPanel)component);
            }
            getHiddenPages().put(component, ti);
    }
   
    List<JPanel> pages = getAllPages();
    if (!pages.contains(component)) //PM:22/07/2008:but only if there are not already stored
      pages.add(index, (JPanel) component);
  }

  @SuppressWarnings("unchecked")
  public List<JPanel> getAllPages() {
    // PM:29/11/07 store all tabs
    List<JPanel> pages = (List<JPanel>) getClientProperty(ALL_PAGES_PROPERTY);
    if (pages == null) {
      pages = new ArrayList<JPanel>();
      putClientProperty(ALL_PAGES_PROPERTY, pages);
    }
    return pages;
  }
 
  @SuppressWarnings("unchecked")
  //PM:22/07/2008:AXA
  public Map<Component, TabInfo> getHiddenPages(){
    return  (Map<Component, TabInfo>)getClientProperty("qq_hidden_pages");
  }
 
 
  /**
   * This flag is used to determine if a tab change was effected from the user clicking the mouse on the tab
   */
  private boolean isSetViaMouse = false;
 
  @Override
  public void setSelectedIndex(final int index) {
    /**
     * PM:22/3/08
     * This is an odd requirement for customers wanting
     * to verify a tab pane before it is changed.
     * So we post and wait
     */
    EventManager.startEventChain();
    Hashtable<String, ParameterHolder> params = new Hashtable<String, ParameterHolder>();
    EventManager.postEventAndWait(this, "BeforeTabChange", params);
//    System.out.println("BeforeTabChange");
        List<JPanel> allPages = this.getAllPages();
        int selectedIndex = getSelectedIndex();
        if (selectedIndex > -1){
          JPanel page = (JPanel)getComponentAt(selectedIndex);
          setPreviousTabIndex(allPages.indexOf(page)+1);
        }
        if (!this.preventChange) {
          super.setSelectedIndex(index);
      // TF:24/3/08:Tab folders default their focus to the first component in the tab if the tab change was caused
      // by a mouse click. We need to defer this event to the end of the EDT queue, even though this method will
      // exist on the EDT queue because the tab component hasn't been set up properly here yet, and may still be invisible
      if (isSetViaMouse) {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            Component c = TabFolder.this.getComponentAt(index);
           
            // CraigM:06/08/2008 - Set the traversal reason to be done by the application
            ForteKeyboardFocusManager.setApplicationTraversal();
           
            if (c.isFocusable()) {
              c.requestFocusInWindow();
            }
            else {
              c.transferFocus();
            }
          }
        });
      }
        }
        this.preventChange = false;
        postTabSelect();
        EventManager.endEventChain();
     
  }
    public void postTabSelect() {
        //PM:26/11/07
        /*
         * Get the actual tab index considering
         * invisible tabs
         */
//      System.out.println("AfterTabSelect");
        int targetIndex = this.getSelectedIndex();
        List<JPanel> allPages = this.getAllPages();
        if (targetIndex > -1){
            JPanel page = (JPanel)this.getComponentAt(targetIndex);
            targetIndex = allPages.indexOf(page)+1;
        }
//        EventManager.startEventChain();
        Hashtable<String, Object> qq_Params = new Hashtable<String, Object>();
        qq_Params.put( "prevIndex", new ParameterHolder(this.getPreviousTabIndex()));
        qq_Params.put( "index", new ParameterHolder(targetIndex) );
        qq_Params.put( "page", new ParameterHolder(this.getSelectedComponent()) );
        ClientEventManager.postEvent(this, "AfterTabSelect", qq_Params);
//        EventManager.endEventChain();
//        this.resetPreviousTabIndex();
    }

    public int getPreviousTabIndex() {
        return this.previousTabIndex;
    }

    public void setPreviousTabIndex(int previousTabIndex) {
      this.previousTabIndex = previousTabIndex;
    }
   
    public void resetPreviousTabIndex() {
        setPreviousTabIndex(getSelectedIndex());
    }

    public void revertTabSelection(int tabIndex) {
        this.ignoreChange = true;
        super.setSelectedIndex(tabIndex);
        this.resetPreviousTabIndex();
        this.ignoreChange = false;
    }

    public boolean shouldIgnoreChange() {
        return this.ignoreChange;
    }

    public void preventChange(){
      this.preventChange = true;
    }
   
  /**
   * Override the processMouseEvent method so we can set a flag to indicate whether we're coming from
   * a mouse click. This is important because Forte set the focus of the tab folder to be the first
   * widget within the tab folder if and only if the tab change was caused by a mouse click.
   */
  @Override
  protected void processMouseEvent(MouseEvent e) {
    this.isSetViaMouse = true;
    super.processMouseEvent(e);
    this.isSetViaMouse = false;
  }
  //PM:21/07/2008:AXA
    public String getUIClassID() {
        return uiClassID;
    }
  //PM:21/07/2008:AXA
    public void updateUI() {
        setUI(TabFolderUI.createUI(this));
        invalidate();
    }
    //PM:22/07/2008:AXA
    @Override
    public void addTab(String title, Component component) {
      insertTab(title, null, component, null, getAllPages().size());
      FrameWeight.set((JComponent)component, Constants.W_NONE);
    }

    public void focusGained(FocusEvent e) {
        EventManager.startEventChain();
        int reason = ForteKeyboardFocusManager.getTraversalReason();
        if (reason != Constants.FC_SUPRESS) {
            Hashtable<String, Object> params = new Hashtable<String, Object>();
            params.put("reason", new ParameterHolder(reason));
            ClientEventManager.postEvent( this, "BeforeFocusLoss", params );
        }
        EventManager.endEventChain();

        // CraigM:21/08/2008 - This is done in setSelectedIndex
//        if (this.getPreviousTabIndex() != this.getSelectedIndex()) {
//          this.postTabSelect();
//        }
    }

    public void focusLost(FocusEvent e) {
        EventManager.startEventChain();
        int reason = ForteKeyboardFocusManager.getTraversalReason();
        if (reason != Constants.FC_SUPRESS) {
            Hashtable<String, Object> params = new Hashtable<String, Object>();
            params.put("reason", new ParameterHolder(reason));
            ClientEventManager.postEvent( this, "BeforeFocusLoss", params );
        }
        EventManager.endEventChain();
    }
   
    @SuppressWarnings("unchecked")
  public void setPages(Array_Of_Panel pages) {
        // add the array of pages
        // TF:13/8/07:Ensure we also remove any existing pages, and reset the size of the panel to 1, 1
        // or there abouts, as Forte did this when setting the tabs
        this.removeAll();
        Map<Component, TabInfo> hiddenPages = this.getHiddenPages();
        List<JPanel> allPages = this.getAllPages();//PM:14/01/2009:get all pages
        allPages.clear();
        if (hiddenPages != null) {
            hiddenPages.clear();
        }

        for (int i = 0; i < pages.size(); i++) {
            JPanel page = (JPanel) pages.get(i);
            TextData caption = Caption.get(page);
            // TF:13/8/07:Panels don't have borders in tab panes
            Border b = page.getBorder();
            if (b instanceof TitledBorder) {
              ((TitledBorder)b).setTitle("");
                ((TitledBorder)b).setBorder(new EmptyBorder(0,0,0,0));
            }
            else {
                page.setBorder(null);
            }
            page.setMinimumSize(null);
            page.setPreferredSize(null);
            page.setSize(1, 1);
           
            addTab(caption.getValue(), page);
           
        }
        this.setSize(1,1);
        this.setMinimumSize(null);
        this.setPreferredSize(null);
    }

    /**
     * Returns the Swing tab index (which doesn't include hidden tabs), based on the index including hidden tabs.
     * CraigM:16/01/2009.
     *
     * @param modelIndex 0 based index including hidden tabs
     * @return 0 based index excluding hidden tabs
     */
    public int getTabIndex(int modelIndex) {
      List<JPanel> allPages = this.getAllPages();
     
      if (allPages != null && modelIndex >= 0 && modelIndex < allPages.size()) {
        JPanel page = allPages.get(modelIndex);
       
        for (int index=0; index<this.getTabCount(); index++) {
          if (this.getComponentAt(index) == page) {
            return index; // Found the page
          }
        }
      }
     
      return -1;
    }
   
    /**
     * Returns the model tab index (which includes hidden tabs), based on the swing index excluding hidden tabs.
     * CraigM:19/01/2009.
     *
     * @param tabIndex 0 based index excluding hidden tabs
     * @return 0 based index including hidden tabs (-1 if not found)
     */
    public int getModelIndex(int tabIndex) {
      try {
        Component page = this.getComponentAt(tabIndex);
          List<JPanel> allPages = this.getAllPages();
          return allPages.indexOf(page);
      }
      catch (IndexOutOfBoundsException e) {
        return -1;
      }
    }

    /**
     * Get list of all the pages in this tab folder. The pages are returned irrespective
     * of their visibility, so that getPages().length != getTabCount() particularly when
     * there are invisible pages. The array returned is a copy of the backing array.
     * @return
     */
    @SuppressWarnings("unchecked")
    public Array_Of_Panel<Panel> getPages() {
      Array_Of_Panel pages = new Array_Of_Panel();
      List<JPanel> allPages = getAllPages();
      for (JPanel page : allPages){
        pages.add(page);
      }
      return pages;
    }

    public void hideTab(JPanel page){
      if (isTabVisible(page)){
        page.setVisible(false);
        page.putClientProperty(IS_TAB_VISIBLE_PROPERTY, false);

        List<JPanel> allPages = getAllPages();
        Map<Component, TabInfo> hiddenPages = getHiddenPages();
        int index = allPages.indexOf(page);
        String caption = getTitleAt(indexOfComponent(page));
        TabInfo ti = (TabInfo)page.getClientProperty(TAB_INFO_PROPERTY);
        if (ti == null) {
          ti = new TabInfo(caption, null, index, page);
        }
        hiddenPages.put(page, ti);
        super.remove(page);
        _log.debug("Setting Tab Invisible: " + caption  );
      }
    }
   
    public void showTab(JPanel page){
      if (!isTabVisible(page)){
       
        page.setVisible(true);//PM:14/01/2009:set to be visible
        page.putClientProperty(IS_TAB_VISIBLE_PROPERTY, true);

        List<JPanel> allPages = getAllPages();
        Map<Component, TabInfo> hiddenPages = getHiddenPages();
        TabInfo ti = (TabInfo) hiddenPages.get(page);
        //PM:22/07/2008: fixed tab order
        int insertIndex = 0;
        JPanel lastVisible = null;
        for (JPanel tab : allPages){
          if (tab == page)
            break;
          if (isTabVisible(tab))
            lastVisible = tab;
        }
        insertIndex = indexOfComponent(lastVisible) + 1;
        super.insertTab(ti.getCaption(), ti.getIcon(), page,
          page.getToolTipText(), insertIndex);
        hiddenPages.remove(page);
        _log.debug("Setting Tab Visible: " + ti.getCaption() );
      }
    }
   
    public boolean isTabVisible(JPanel jp){
      return (Boolean)jp.getClientProperty(IS_TAB_VISIBLE_PROPERTY);
    }

}
TOP

Related Classes of DisplayProject.controls.TabFolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.