Package simtools.ui

Source Code of simtools.ui.SplitTabPane

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2005, by :
*     Corporate:
*         EADS Astrium SAS
*         EADS CRC
*     Individual:
*         Claude Cazenave
*
* $Id: SplitTabPane.java,v 1.3 2006/06/08 09:50:21 ogor Exp $
*
* Changes
* -------
* 9 d�c. 2005 : Initial public release (CC);
*
*/
package simtools.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import javax.swing.JDialog;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.border.TitledBorder;

/**
* A split tab pane is a JPanel in charge of the layout of several sub panel elements
* 3 kind of layouts are available
* TAB mode : a JTabbedPane is used to display the elements and a card with the element name
* allows to select it
* SPLIT mode : the element is displayed under the JTabbedPane (it one element uses this mode) and
* JSplitPane are used to separate the elements using this mode and thus the user can define the split
* location
* DETACHED mode : the element is not displayed in this panel but in a "detached" dialog. When the user
* closes the dialog the element comes back in this panel with its previous mode (TAB or SPLIT) layout
* All the layout parameters are saved and restore in/from the UserProperties
*/
public class SplitTabPane extends JPanel implements MouseListener, NamedElementContainer {
 
  /** The resources used for the popup menu */
  public static MenuResourceBundle resources = (MenuResourceBundle)ResourceFinder.get(SplitTabPane.class);

  /** The SPLIT mode id */
  public static final int SPLIT = 0;

  /** The TAB mode id */
  public static final int TAB = 1;
 
  /** The DETACHED mode id */
  public static final int DETACHED = 2;

  /** The elements list */
  protected ArrayList elements;

  /** The tab pane, null if no element currently in this mode */
  protected JTabbedPane tabPane;

  /** The wrapper for the first element in SPLIT mode */
  protected SplitBorder firstSplitBorder;

  /** The split used between the elements in SPLIT mode and the element in TAB mode */
  protected JSplitPane tabSplit;

  /** define the panel orientation, i.e. VERTICAL or horizontal */
  protected int orientation;

  /** the popup to "split" a "tab" element */
  protected PopupMenu splitPopup;

  /** the popup to "tab" a "split" element */
  protected PopupMenu unsplitPopup;
 
  /** allow to split/unsplit
   * if not allowed then components stay in their intial mode or can be detached */
  protected boolean allowSplit;
 
  /** allow to detach components */
  protected boolean allowDetached;

  /** the Frame owner used as the owner of the created dialogs in detached mode */
  protected Frame owner;
 
  /**
   * Creates a new panel without elements
   * @param owner used as the owner of the created dialogs in detached mode
   * @param orientation JSplitPane.HORIZONTAL_SPLIT or JSplitPane.VERICAL_SPLIT
   * @param allowSplit
   * @param allowDetached
   */
  public SplitTabPane(Frame owner, int orientation,
      boolean allowSplit,
      boolean allowDetached) {
    super(new BorderLayout());
    this.owner=owner;
    this.orientation = orientation;
    this.allowSplit = allowSplit;
    this.allowDetached = allowDetached;
    elements = new ArrayList();
    createPopups();
  }


  /**
   * Checks if an element is visible
   * @param name the element name
   * @return true if it is visible
   */
  public boolean isVisible(String name){
    for (int i = 0; i < elements.size(); i++) {
      Element e = (Element) elements.get(i);
      if (e.name.equals(name)) {
        return e.comp.isVisible();
      }
    }
    return false;
  }
 
  /**
   * Gets the element knowing the displayed component
   * @param c the component
   * @return the element
   */
  public Element getElement(Component c){
    return (Element)elements.get(getElementIndex(c));
  }
 
  /**
   * Gets the element index knowing the displayed component
   * @param c the component
   * @return the element index
   */
  public int getElementIndex(Component c){
    for (int i = 0; i < elements.size(); i++) {
      Element e = (Element) elements.get(i);
      if (e.comp == c) {
        return i;
      }
    }
    return -1;
  }
 
  /**
   * Change the display mode of one element
   * @param c the component to change
   * @param newMode the new mode
   */
  public void changeElement(Component c, int newMode) {
    int i = getElementIndex(c);
    Element e = (Element) elements.get(i);
    int previousMode=e.getMode();
    if(previousMode!=newMode){
      removeElement(e);
      addElement(e.comp, e.name, newMode, i);
      getElement(e.comp).setPreviousMode(previousMode);
      revalidate();
      repaint();
    }
  }

  /* (non-Javadoc)
   * @see simtools.ui.NamedElementContainer#addElement(java.awt.Component, java.lang.String)
   */
  public void addElement(Component comp, String name) {
    addElement(comp, name, TAB);
  }

  /**
   * Add a new element at the last index
   *
   * @param c the component to be displayed
   * @param name its name
   * @param mode the mode to be used
   */
  public void addElement(Component c, String name, int mode) {
    addElement(c, name, mode, elements.size());
  }

  /**
   * Add a new element at the given index
   * @param c the component to be displayed
   * @param name its name
   * @param mode the mode to be used
   * @param index the index in the list of exisiting elements
   */
  protected void addElement(Component c, String name, int mode, int index) {
    if (mode == SPLIT) {
      if (firstSplitBorder == null) {
        firstSplitBorder = createSplitBorder(c, name);
        if (tabPane != null) { // there is alrady one tab pane
          removeAll();
          tabSplit = new JSplitPane(orientation, tabPane, firstSplitBorder);
          elements.add(index, createElement(c, name, tabSplit,firstSplitBorder));
          add(tabSplit);
        } else { // we dont need a split yet
          elements.add(index, createElement(c, name, firstSplitBorder,firstSplitBorder));
          add(firstSplitBorder);
        }
      } else {
        // there is split area, add this panel to it
        Element p=getElement(firstSplitBorder.comp);
        if (p.owner == p.border) {
          // first split to be created
          removeAll();
          SplitBorder sb=createSplitBorder(c, name);
          JSplitPane sp= new JSplitPane(orientation, p.border, sb);
          p.owner = sp;
          elements.add(index, createElement(c, name, sp,sb));
          add(sp);
        }
        else{
          JSplitPane prev=(JSplitPane)p.owner;
          while(prev.getRightComponent() instanceof JSplitPane){
            // go to latest split
            prev=(JSplitPane)prev.getRightComponent();
          }
          SplitBorder right=(SplitBorder)prev.getRightComponent();
          p=getElement(right.comp);
          if(p.owner!=prev){ // cross check
            throw new RuntimeException(
            "SplitTabPane unexpected state : invalid owner "+p.comp+" "+p.owner);
          }
          SplitBorder sb=createSplitBorder(c, name);
          JSplitPane split = new JSplitPane(orientation, right,
                sb);
          p.owner = split;
          elements.add(index, createElement(c, name, split,sb));
          prev.setRightComponent(split);
        }
      }
    } else if(mode==TAB) {
      if (tabPane == null) {
        tabPane = new JTabbedPane(
            orientation == JSplitPane.HORIZONTAL_SPLIT ? JTabbedPane.LEFT
                : JTabbedPane.TOP);
        tabPane.addMouseListener(this);
        if (firstSplitBorder == null) {
          // we dont need a split yet
          removeAll();
          add(tabPane);
        } else {
          removeAll();
          Element e=getElement(firstSplitBorder.comp);
          tabSplit = new JSplitPane(orientation, tabPane, e.owner);
          if(e.owner == e.border){
            e.owner=tabSplit;
          }
          add(tabSplit);
        }
      }
      // compute the tabIndex
      int tabIndex = 0;
      for (int i = index - 1; i >= 0; i--) {
        Element p = (Element) elements.get(i);
        if (p.owner == tabPane) {
          tabIndex = tabPane.indexOfComponent(p.comp) + 1;
          break;
        }
      }
      tabPane.insertTab(name, null, c, null, tabIndex);
      elements.add(index, createElement(c, name, tabPane,null));
    }
    else if(mode==DETACHED){
      JDialog jd=createDialog(c,name);
      elements.add(index, createElement(c, name, jd,null));
    }
  }

  /**
   * Remove an element from the list
   * The removed element is not foreseen to be reused
   * @param e the element to be removed
   */
  protected void removeElement(Element e) {
    if (e.owner == tabPane) {
      tabPane.remove(e.comp);
      if (tabPane.getTabCount() == 0) {
        // remove the tabPane
        tabPane = null;
        removeAll();
        if(firstSplitBorder!=null){
          Element ef=getElement(firstSplitBorder.comp);
          Component c=ef.owner;
          if(tabSplit==c){
            add(ef.border);
            ef.owner=ef.border;
          }
          else{
            add(c);
          }
        }
        tabSplit = null;
      }
    } else if (e.owner == e.border) {
      removeAll();
      firstSplitBorder=null;
    } else if (e.owner instanceof JSplitPane) {
      JSplitPane sp = (JSplitPane) e.owner;
      if ((sp.getLeftComponent() instanceof SplitBorder)
          && ((SplitBorder) (sp.getLeftComponent())).comp == e.comp) {
        Component r=sp.getRightComponent();
        if(sp.getParent() instanceof JSplitPane){
          JSplitPane previous = (JSplitPane)sp.getParent();
          sp.removeAll();
          previous.setRightComponent(r);
          if(r instanceof SplitBorder){
            SplitBorder b=(SplitBorder)r;
            Element eb=(Element)getElement(b.comp);
            if(previous.getLeftComponent()==tabPane){
              firstSplitBorder=b;
            }
            eb.owner=previous;
          }
          else if(r instanceof JSplitPane){
          }
          else {
            throw new RuntimeException(
                "SplitTabPane unexpected state : right component = "+r);
          }
        }
        else if(sp.getParent()==this){
          sp.removeAll();
          removeAll();
          add(r);
          if(r instanceof SplitBorder){
            SplitBorder b=(SplitBorder)r;
            Element eb=(Element)getElement(b.comp);
            eb.owner=b;
            firstSplitBorder=b;
          }
          else if(r instanceof JSplitPane){
            firstSplitBorder=(SplitBorder)((JSplitPane)r).getLeftComponent();
          }
          else {
            throw new RuntimeException(
                "SplitTabPane unexpected state : right component = "+r);
          }
        }
        else{
          throw new RuntimeException(
          "SplitTabPane unexpected state : root split is not owned by this");
        }
      } else if ((sp.getRightComponent() instanceof SplitBorder)
          && ((SplitBorder) (sp.getRightComponent())).comp == e.comp) {
        Component left = sp.getLeftComponent();
        if (left instanceof JSplitPane) {
          throw new RuntimeException(
              "SplitTabPane unexpected state : left element is a split");
        } else {
          if (left == tabPane) {
            // remove the last split
            removeAll();
            if (tabPane != null) {
              add(tabPane);
            }
            if (firstSplitBorder.comp != e.comp) {
              throw new RuntimeException(
                  "SplitTabPane unexpected state : last split is inconsistent");
            }
            firstSplitBorder = null;
            tabSplit = null;
          } else {
            if(left instanceof SplitBorder){
              SplitBorder b=(SplitBorder)left;
              Element eb=(Element)getElement(b.comp);
              sp.removeAll();
              if(sp.getParent()==this){
                removeAll();
                add(left);
                firstSplitBorder=(SplitBorder)left;
                eb.owner=b;
              }
              else if(sp.getParent() instanceof JSplitPane){
                JSplitPane parent=(JSplitPane)sp.getParent();
                parent.setRightComponent(left);
                if(parent.getLeftComponent()==tabPane){
                  firstSplitBorder=(SplitBorder)left;
                }
                eb.owner=parent;
              }
              else{
                throw new RuntimeException(
                "SplitTabPane unexpected state : invalid parent ="+sp.getParent());
              }
            }
            else {
              throw new RuntimeException(
                "SplitTabPane unexpected state : left="+left);
            }
          }
        }
      } else {
        throw new RuntimeException(
            "SplitTabPane unexpected state : inconsistent owner ="+e.owner+"\n"+
            "Left="+sp.getLeftComponent()+"\n"+
            "Right="+sp.getRightComponent());
      }
    } else if(e.owner instanceof JDialog){
      JDialog jd=(JDialog)e.owner;
      jd.setVisible(false);
      jd.getContentPane().removeAll();
    }
    else {
      throw new RuntimeException(
          "SplitTabPane unexpected state : invalid owner");
    }
    e.border=null;
    e.owner=null;
    elements.remove(e);
  }

  /**
   * Create the popups that allows the user to change elements layout mode
   * To be oveverridden if needed !
   */
  protected void createPopups() {
    if(allowSplit || allowDetached){
      splitPopup = new PopupMenu(TAB);
      unsplitPopup = new PopupMenu(SPLIT);
    }
  }

  /**
   * Create the dialog used in DETACHED mode
   * To be oveverridden if needed !
   * @param c the component to be displayed
   * @param name the name used as a dialog title
   * @return the dialog
   */
  protected JDialog createDialog(final Component c, String name){
    JDialog jd=new JDialog(owner, name);
    jd.getContentPane().add(c);
    jd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    jd.addWindowListener(new WindowAdapter(){

      public void windowClosed(WindowEvent e) {
        Element el=getElement(c);
        changeElement(c,el.previousMode);
      }
    });
    jd.pack();
    jd.show();
    return jd;
  }
 
  public void save(UserProperties up, String suffix){
    String propRoot=SplitTabPane.class.getName();
    if(suffix!=null){
      propRoot=propRoot+"."+suffix;
    }
    for(int i=0;i<elements.size();i++){
      Element e=(Element)elements.get(i);
      e.save(up, propRoot);
    }
  }
 
  public void load(UserProperties up, String suffix){
    String propRoot=SplitTabPane.class.getName();
    if(suffix!=null){
      propRoot=propRoot+"."+suffix;
    }
    for(int i=0;i<elements.size();i++){
      Element e=(Element)elements.get(i);
      e.load(up, propRoot);
    }
  }
 
  //=========================================
  // mouse listener interface
  //=========================================
  public void mouseClicked(MouseEvent e) {
  }

  public void mouseEntered(MouseEvent e) {
  }

  public void mouseExited(MouseEvent e) {
  }

  public void mouseReleased(MouseEvent e) {
  }

  public void mousePressed(MouseEvent e) {
    if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) == MouseEvent.BUTTON3_MASK) {
      if (e.getSource() == tabPane) {
        splitPopup.show(tabPane, e.getX(), e.getY());
      } else {
        SplitBorder sb=(SplitBorder) e.getSource();
        unsplitPopup.comp=sb.comp;
        unsplitPopup.show(sb, e.getX(), e.getY());
      }
    }
  }

  // -------------------------------------------------------
  // inner classes
  // -------------------------------------------------------

  /**
   * Create the panel used in SPLIT mode to display the component inside
   * JSplitPane.
   * To be oveverridden if needed !
   * @param c the component to be displayed
   * @param name the name used as a dialog title
   * @return the panel
   */
  protected SplitBorder createSplitBorder(Component c, String name){
    return new SplitBorder(c,name);
  }
 
  /**
   * The default wrapper for the components when in SPLIT mode
   * A JPanel with a TitledBorder containing the element name
   * This panel has also a mouse listener for the popup menu
   */
  protected class SplitBorder extends JPanel {

    protected final Component comp;

    protected SplitBorder(Component c, String name) {
      super(new BorderLayout());
      comp = c;
      add(comp);
      TitledBorder b = new TitledBorder(name);
      setBorder(b);
      addMouseListener(SplitTabPane.this);
    }

    /**
     * @return Returns the comp.
     */
    public Component getComp() {
      return comp;
    }
   
   
  }

  /**
   * Create the Element, the internal structure describing the managed components
   * To be oveverridden if needed !
   * @param c the component to be displayed
   * @param n the name of the component
   * @param o the container owner of this component (a JSplitPane, a JDialog, a JTabbedPane or this)
   * @parame b the wrapper in SPLIT mode
   * @return the element
   */
  protected Element createElement(Component c, String n, Container o, SplitBorder b) {
    return new Element(c,n,o,b);
  }
 
  /**
   * Element is the internal structure describing the managed components
   * @return the element
   */
  protected class Element {
    /** the component to be displayed */
    final Component comp;

    /** the wrapper in SPLIT mode */
    SplitBorder border;
   
    /** the container owner of this component (a JSplitPane, a JDialog, a JTabbedPane or this) */
    Container owner;

    /** the name of the component */
    final String name;
   
    /** the previous mode of this component used when the dialog is closed in detached mode */
    int previousMode=TAB;

    /**
     * Creates a new element
     * @param c the component to be displayed
     * @param n the name of the component
     * @param o the container owner of this component (a JSplitPane, a JDialog, a JTabbedPane or this)
     * @parame b the wrapper in SPLIT mode
     */
    protected Element(Component c, String n, Container o, SplitBorder b) {
      comp = c;
      owner = o;
      name = n;
      border=b;
    }

    /**
     * @return Returns the previous mode.
     */
    public int getPreviousMode() {
      return previousMode;
    }

    /**
     * @param previousMode The previous mode to set.
     */
    public void setPreviousMode(int previousMode) {
      this.previousMode = previousMode;
    }

    /**
     * @return Returns the name.
     */
    public String getName() {
      return name;
    }

    /**
     * @return Returns the owner.
     */
    public Container getOwner() {
      return owner;
    }
   
    /**
     * @return the element mode
     */
    public int getMode(){
      if(owner instanceof JDialog){
        return DETACHED;
      }
      else if(owner instanceof JTabbedPane){
        return TAB;
      }
      else{
        return SPLIT;
      }
    }
   
    public String getPropertyName(String propRoot){
      return propRoot+"."+name.replaceAll("[ \t]","_");
    }
   
    public void save(UserProperties up, String propRoot){
      propRoot=getPropertyName(propRoot);
      up.setInt(propRoot+".MODE", getMode());
      up.setInt(propRoot+".PREVIOUS_MODE", getPreviousMode());
      if(getMode()==SPLIT){
        if(owner instanceof JSplitPane){
          up.setInt(propRoot+".DIVIDER", ((JSplitPane)owner).getDividerLocation());
        }
       
      }
      else if(getMode()==DETACHED){
        JDialog jd=(JDialog)owner;
        up.setInt(propRoot+".X", jd.getX());
        up.setInt(propRoot+".Y", jd.getY());
        up.setInt(propRoot+".WIDTH", jd.getWidth());
        up.setInt(propRoot+".HEIGHT", jd.getHeight());
      }
    }
   
    public void load(UserProperties up, String propRoot){
      propRoot=getPropertyName(propRoot);
      int mode=up.getInt(propRoot+".MODE",-1);
      if(mode<0){
        return;
      }
      previousMode=up.getInt(propRoot+".PREVIOUS_MODE",previousMode);
      Element e=this;
      if(mode!=getMode()){
        changeElement(comp,mode);
        e=getElement(comp);
      }
      if(e.getMode()==SPLIT){
        if(e.owner instanceof JSplitPane){
          ((JSplitPane)e.owner).setDividerLocation(
              up.getInt(propRoot+".DIVIDER", 10));
        }
      }
      else if(e.getMode()==DETACHED){
        JDialog jd=(JDialog)e.owner;
        int x=up.getInt(propRoot+".X",0);
        int y=up.getInt(propRoot+".Y", 0);
        int w=up.getInt(propRoot+".WIDTH", 100);
        int h=up.getInt(propRoot+".HEIGHT", 100);
        jd.setSize(w,h);
        jd.validate();
        jd.setLocation(x,y);
      }
    }
  }

  /**
   * The default popup used to provide control on the layout mode
   */
  public class PopupMenu extends JPopupMenu implements ActionListener {

    private JMenuItem _miChange;
    private JMenuItem _miDetached;

    private int mode;
    Component comp;

    /**
     * Constructs a new PopupMenu instance
     */
    public PopupMenu(int mode) {
      this.mode = mode;
      if(allowSplit){
        add(_miChange = resources.getItem((mode == SPLIT ? "unsplit" : "split"), this));
      }
      if(allowDetached){
        add(_miDetached = resources.getItem("detached", this));
      }
    }

    //
    // ActionListener interface
    //
    public void actionPerformed(ActionEvent e) {
      if (e.getSource() == _miChange) {
        if (mode == TAB) {
          changeElement(tabPane.getSelectedComponent(), SPLIT);
        } else {
          changeElement(comp, TAB);
        }
      }
      else if (e.getSource() == _miDetached) {
        if (mode == TAB) {
          changeElement(tabPane.getSelectedComponent(), DETACHED);
        } else {
          changeElement(comp, DETACHED);
        }
      }
    }
  }
}
TOP

Related Classes of simtools.ui.SplitTabPane

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.