home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / SplitterPanel.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  54.9 KB  |  1,937 lines

  1. package symantec.itools.awt;
  2.  
  3.  
  4. import java.awt.Panel;
  5. import java.awt.Component;
  6. import java.awt.Dimension;
  7. import java.awt.Frame;
  8. import java.awt.Point;
  9. import java.awt.Color;
  10. import java.awt.Rectangle;
  11. import java.awt.LayoutManager;
  12. import java.awt.Graphics;
  13. import java.awt.Container;
  14. import java.awt.Event;
  15.  
  16.  
  17. /**
  18.  * Creates a container that can be divided into a number of subpanels which 
  19.  * holds visual components and other panels, and specifically to:
  20.  * <UL>
  21.  * <DT>╖ create a subcontainer that organizes container space within an Applet,
  22.  * Frame or Dialog container. This simplifies your component layout task.</DT>
  23.  * <DT>╖ hold other specialized Panel containers.</DT>
  24.  * </UL>
  25.  * The SplitterPanel component is the parent Panel containing a set of 
  26.  * subpanels. You must write code to divide the parent panel into subpanels. 
  27.  * You must set panel defaults in your project source code, but can drop 
  28.  * components into subpanels from the Palette. 
  29.  * <p>
  30.  * SplitterPanel automatically recognizes the MouseDrag event as the command 
  31.  * to resize the appropriate subpanel boundary.
  32.  * <p>
  33.  * Subpanels can be resized at runtime by dragging panel borders with the mouse.
  34.  * <p>
  35.  * This code example splits a SplitterPanel into four subpanels and adds a 
  36.  * button to two of the subpanels.
  37.  * <UL><pre>
  38.  * splitterPanel1.split(splitterPanel1.SPLIT_HOR);
  39.  * splitterPanel1.getTopPanel().split(splitterPanel1.SPLIT_VER);
  40.  * splitterPanel1.getBottomPanel().split(splitterPanel1.SPLIT_VER);
  41.  * // add a button to the top left panel
  42.  * splitterPanel1.getTopLeftPanel().add(new Button("Top Left"));
  43.  * // add a button to the lower right panel
  44.  * splitterPanel1.getBottomRightPanel().add(new Button("Bottom Right"));
  45.  * </pre></UL>
  46.  * Individual subpanels can be accessed in code using any of these methods: 
  47.  * getBottomLeftPanel,
  48.  * getBottomPanel,
  49.  * getBottomRightPanel,
  50.  * getLeftPanel,
  51.  * getRightPanel,
  52.  * getSub2Panel,
  53.  * getSubPanel,
  54.  * getTopLeftPanel,
  55.  * getTopPanel,
  56.  * getTopRightPanel.
  57.  * <p>
  58.  * @version 1.0, Nov 26, 1996
  59.  *
  60.  * @author  Symantec
  61.  *
  62.  */
  63.  
  64. public class SplitterPanel
  65.     extends Panel
  66. {
  67.     //--------------------------------------------------
  68.     // constants
  69.     //--------------------------------------------------
  70.  
  71.     /**
  72.      * Vertical panel split definition.  The panel contains/will
  73.      * contain two subpanels, left and right.
  74.      * @see #split
  75.      */
  76.     public static final int SPLIT_VER  = 1;
  77.  
  78.     /**
  79.      * Horizontal panel split definition.  The panel contains/will
  80.      * contain two subpanels, top and bottom.
  81.      * @see #split
  82.      */
  83.     public static final int SPLIT_HOR  = 2;
  84.  
  85.     /**
  86.      * Vertical pane split constant for the SplitterPanel constructor.
  87.      * This splits the pane into two vertical panes.
  88.      * @see #SplitterPanel
  89.      */
  90.     public static final int SPLIT_VERTICAL      = 1;
  91.  
  92.     /**
  93.      * Horizontal pane split constant for the SplitterPanel constructor.
  94.      * This splits the pane into two horizontal panes.
  95.      * @see #SplitterPanel
  96.      */
  97.     public static final int SPLIT_HORIZONTAL    = 2;
  98.  
  99.     /**
  100.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  101.      * This splits the pane into four panes.
  102.      * @see #SplitterPanel
  103.      */
  104.     public static final int SPLIT_BOTH          = 3;
  105.  
  106.     /**
  107.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  108.      * This splits the pane into four panes.
  109.      * @see #SplitterPanel
  110.      */
  111.     public static final int SPLIT_BOTH_V        = 4;
  112.  
  113.     /**
  114.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  115.      * This splits the pane into three panes, with a single larger pane on the
  116.      * right.
  117.      * @see #SplitterPanel
  118.      */
  119.     public static final int SPLIT3_LEFT         = 5;
  120.  
  121.     /**
  122.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  123.      * This splits the pane into three panes, with a single larger pane on the
  124.      * left.
  125.      * @see #SplitterPanel
  126.      */
  127.     public static final int SPLIT3_RIGHT        = 6;
  128.  
  129.     /**
  130.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  131.      * This splits the pane into three panes, with a single larger pane on the
  132.      * bottom.
  133.      * @see #SplitterPanel
  134.      */
  135.     public static final int SPLIT3_TOP          = 7;
  136.  
  137.     /**
  138.      * Vertical/Horizontal pane split constant for the SplitterPanel constructor.
  139.      * This splits the pane into three panes, with a single larger pane on the
  140.      * top.
  141.      * @see #SplitterPanel
  142.      */
  143.     public static final int SPLIT3_BOTTOM       = 8;
  144.  
  145.     private static final int SPLIT_NONE = 0;   //Panel contains no subpanels, initial state
  146.  
  147.  
  148.     //--------------------------------------------------
  149.     // class variables
  150.     //--------------------------------------------------
  151.  
  152.     /**
  153.      * This flag specifies how to draw border around panes.
  154.      * Must be used in conjunction with setBdrSizes or other setXXX
  155.      * calls to take effect.
  156.      */
  157.     public boolean use3dBdr = true;
  158.     private boolean enforceMinDim = false;
  159.     private boolean propResize = true;
  160.  
  161.     /**
  162.      * Determines the cursor to use when drag the split between panes.
  163.      * Use Frame.HAND_CURSOR, etc to choose a cursor or
  164.      * set to Integer.MIN_VALUE to prevent cursor change.
  165.      * @see java.awt.Frame
  166.      */
  167.     public int moveSplitCursor = Frame.MOVE_CURSOR;
  168.     private int splitType;
  169.     private boolean isOuter;
  170.     private Dimension curDim;
  171.     private Point curLoc;
  172.     private boolean dimChanged;
  173.     private boolean heightOnly;
  174.     private boolean widthOnly;
  175.     private boolean doMoveSplit = false;
  176.     private boolean cursorChanged = false;
  177.     private int moveFromX;
  178.     private int moveFromY;
  179.     private Component spComponent;
  180.     private SplitterPanel sub1;
  181.     private SplitterPanel sub2;
  182.     private SplitterPanel innerSP;
  183.     private SplitterPanel outerSP;
  184.     static private SplitterPanel cursorCh = null;
  185.  
  186.     /**
  187.      * Dimension variables.
  188.      * Note that these should be set explicitly if you wish to override
  189.      * the built in calculation of these dimensions.  For instance, do
  190.      * not set (or set to zeros), the value for prefDim if you want the
  191.      * SplitterPanel to calculate this as the sum of the subcomponents
  192.      * prefDims.  minDim is used when the user explicitly sets the
  193.      * minimum size; prefDim is used when the user explicitly sets the
  194.      * preferred size.
  195.      */
  196.     private Dimension minDim;
  197.     private Dimension prefDim;
  198.     private Color gapColor;
  199.     private int iGapWidth;
  200.     private int iGapHeight;
  201.     private int oGapWidth;
  202.     private int oGapHeight;
  203.     private int iBdrSize;
  204.     private int oBdrSize;
  205.     private boolean bOsFlag;
  206.  
  207.  
  208.     //--------------------------------------------------
  209.     // constructors
  210.     //--------------------------------------------------
  211.  
  212.     /**
  213.      * Constructs a new default SplitterPanel.
  214.      */
  215.     public SplitterPanel()
  216.     {
  217.         this(true);
  218.     }
  219.  
  220.     /**
  221.      * Constructs a new SplitterPanel of the specified size which
  222.      * is ready to be split into panes.
  223.      * @param spWidth value to be used for the initial width of
  224.      * the SplitterPanel
  225.      * @param spHeight value to be used for the initial height of
  226.      * the SplitterPanel
  227.      */
  228.     public SplitterPanel(int spWidth, int spHeight)
  229.     {
  230.         this(true);
  231.  
  232.         if (this == null)
  233.             return;
  234.  
  235.         resize(spWidth, spHeight);
  236.     }
  237.  
  238.     /**
  239.      * Constructs a new SplitterPanel of specified size which is
  240.      * split into panes.
  241.      * @param spWidth value to be used for the initial width of
  242.      * the SplitterPanel
  243.      * @param spHeight value to be used for the initial height
  244.      * of the SplitterPanel
  245.      * @param splitSpec specifies the type of split
  246.      * @see #SPLIT_VERTICAL
  247.      * @see #SPLIT_HORIZONTAL
  248.      * @see #SPLIT_BOTH
  249.      * @see #SPLIT_BOTH_V
  250.      * @see #SPLIT3_LEFT
  251.      * @see #SPLIT3_RIGHT
  252.      * @see #SPLIT3_TOP
  253.      * @see #SPLIT3_BOTTOM
  254.      */
  255.     public SplitterPanel(int spWidth, int spHeight, int splitSpec)
  256.     {
  257.         this(splitSpec);
  258.  
  259.         if (this == null)
  260.             return;
  261.  
  262.         resize(spWidth, spHeight);
  263.     }
  264.  
  265.     /**
  266.      * Constructs a new SplitterPanel which is split into panes.
  267.      * @param splitSpec specifies the type of split
  268.      * @see #SPLIT_VERTICAL
  269.      * @see #SPLIT_HORIZONTAL
  270.      * @see #SPLIT_BOTH
  271.      * @see #SPLIT_BOTH_V
  272.      * @see #SPLIT3_LEFT
  273.      * @see #SPLIT3_RIGHT
  274.      * @see #SPLIT3_TOP
  275.      * @see #SPLIT3_BOTTOM
  276.      */
  277.     public SplitterPanel(int splitSpec)
  278.     {
  279.         this(splitSpec, null, null, null, null);
  280.     }
  281.  
  282.     /**
  283.      * Constructs a new SplitterPanel which is split into panes
  284.      * to which components are added.
  285.      * @param splitSpec specifies the type of split
  286.      * @see #SPLIT_VERTICAL
  287.      * @see #SPLIT_HORIZONTAL
  288.      * @see #SPLIT_BOTH
  289.      * @see #SPLIT_BOTH_V
  290.      * @see #SPLIT3_LEFT
  291.      * @see #SPLIT3_RIGHT
  292.      * @see #SPLIT3_TOP
  293.      * @see #SPLIT3_BOTTOM
  294.      * @param compR1C1 specifies the component in row 1, column 1
  295.      * @param compR1C2 specifies the component in row 1, column 2
  296.      * @param compR2C1 specifies the component in row 2, column 1
  297.      * @param compR2C2 specifies the component in row 2, column 2
  298.      */
  299.     public SplitterPanel(int splitSpec, Component compR1C1, Component compR1C2, Component compR2C1, Component compR2C2)
  300.     {
  301.         this(true);
  302.  
  303.         if (this == null)
  304.             return;
  305.  
  306.         switch (splitSpec)
  307.         {
  308.  
  309.             case SPLIT_NONE:
  310.             {
  311.                 if (compR1C1 != null) this.add(compR1C1);
  312.                 break;
  313.             }
  314.  
  315.             case SPLIT_VERTICAL:
  316.             {
  317.                 split(SPLIT_VER, compR1C1, compR1C2);
  318.                 break;
  319.             }
  320.  
  321.             case SPLIT_HORIZONTAL:
  322.             {
  323.                 split(SPLIT_HOR, compR1C1, compR2C1);
  324.                 break;
  325.             }
  326.  
  327.             case SPLIT_BOTH:
  328.             {
  329.                 split(SPLIT_HOR);
  330.                 getSubPanel(1).split(SPLIT_VER, compR1C1, compR1C2);
  331.                 getSubPanel(2).split(SPLIT_VER, compR2C1, compR2C2);
  332.                 break;
  333.             }
  334.  
  335.             case SPLIT_BOTH_V:
  336.             {
  337.                 split(SPLIT_VER);
  338.                 getSubPanel(1).split(SPLIT_HOR, compR1C1, compR2C1);
  339.                 getSubPanel(2).split(SPLIT_HOR, compR1C2, compR2C2);
  340.                 break;
  341.             }
  342.  
  343.             case SPLIT3_LEFT:
  344.             {
  345.                 split(SPLIT_VER, null, compR1C2);
  346.                 getSubPanel(1).split(SPLIT_HOR, compR1C1, compR2C1);
  347.                 break;
  348.             }
  349.  
  350.             case SPLIT3_RIGHT:
  351.             {
  352.                 split(SPLIT_VER, compR1C1, null);
  353.                 getSubPanel(2).split(SPLIT_HOR, compR1C2, compR2C2);
  354.                 break;
  355.             }
  356.  
  357.             case SPLIT3_TOP:
  358.             {
  359.                 split(SPLIT_HOR, null, compR2C1);
  360.                 getSubPanel(1).split(SPLIT_VER, compR1C1, compR1C2);
  361.                 break;
  362.             }
  363.  
  364.             case SPLIT3_BOTTOM:
  365.             {
  366.                 split(SPLIT_HOR, compR1C1, null);
  367.                 getSubPanel(2).split(SPLIT_VER, compR2C1, compR2C2);
  368.                 break;
  369.             }
  370.  
  371.         }
  372.     }
  373.  
  374.     private SplitterPanel(boolean isOuter)
  375.     {
  376.         super();
  377.  
  378.         this.isOuter = isOuter;
  379.         dimChanged = true;
  380.         heightOnly = false;
  381.         widthOnly  = false;
  382.         splitType = SPLIT_NONE;
  383.  
  384.         setLayout(null);
  385.  
  386.         // Set defaults
  387.         minDim  = new Dimension(0, 0);
  388.         curDim  = new Dimension(0, 0);
  389.         curLoc  = new Point(0, 0);
  390.         prefDim = new Dimension(0, 0);
  391.  
  392.         gapColor = Color.lightGray;
  393.  
  394.         iGapWidth  = 3;
  395.         iGapHeight = 3;
  396.         iBdrSize   = 2;
  397.         oGapWidth  = 3;
  398.         oGapHeight = 3;
  399.         oBdrSize   = 2;
  400.  
  401.         //If outer, then create the REQUIRED first inner Panel
  402.         if (isOuter)
  403.         {
  404.             innerSP = new SplitterPanel(false);
  405.             super.add(innerSP, -1);
  406.             outerSP = this;
  407.             innerSP.outerSP = this;
  408.         }
  409.  
  410.     }
  411.  
  412.     //--------------------------------------------------
  413.     // accessor methods
  414.     //--------------------------------------------------
  415.  
  416.     /**
  417.      * Sets the color of the gap between panes and around the outside
  418.      * border.
  419.      * @param c the color to use
  420.      * @see #getGapColor
  421.      */
  422.     public void setGapColor(Color c)
  423.     {
  424.         this.gapColor = new Color(c.getRed(), c.getGreen(), c.getBlue());
  425.         propagateChanges();
  426.     }
  427.  
  428.     /**
  429.      * Gets the color of the gap between panes and around
  430.      * the outside.
  431.      * @return current gap color
  432.      * @see #setGapColor
  433.      */
  434.     public Color getGapColor()
  435.     {
  436.         return gapColor;
  437.     }
  438.  
  439.     private void adjustOGapBdr()
  440.     {
  441.         if (this.oGapWidth  < this.oBdrSize)
  442.             this.oGapWidth  = Math.max(0, this.oBdrSize);
  443.  
  444.         if (this.oGapHeight < this.oBdrSize)
  445.             this.oGapHeight = Math.max(0, this.oBdrSize);
  446.     }
  447.  
  448.     /**
  449.      * Sets the size of the gap between panes and around the
  450.      * outside.
  451.      * @param gapSize the size in pixels
  452.      */
  453.     public void setGapSizes(int gapSize)
  454.     {
  455.         this.iGapWidth  = gapSize;
  456.         this.iGapHeight = gapSize;
  457.         this.oGapWidth  = gapSize;
  458.         this.oGapHeight = gapSize;
  459.         adjustOGapBdr();
  460.         propagateChanges();
  461.         invalidate();
  462.     }
  463.  
  464.     /**
  465.      * Sets the size of the gap between panes and around the
  466.      * outside.
  467.      * @param gapWidth the size in pixels
  468.      * @param gapHeight the size in pixels
  469.      */
  470.     public void setGapSizes(int gapWidth, int gapHeight)
  471.     {
  472.         this.iGapWidth  = gapWidth;
  473.         this.iGapHeight = gapHeight;
  474.         this.oGapWidth  = gapWidth;
  475.         this.oGapHeight = gapHeight;
  476.         adjustOGapBdr();
  477.         propagateChanges();
  478.         invalidate();
  479.     }
  480.  
  481.     /**
  482.      * Sets the size of the gap between panes and around the
  483.      * outside.
  484.      * @param iGapWidth the size in pixels between panes
  485.      * @param iGapHeight the size in pixels between panes
  486.      * @param oGapWidth the size in pixels around the outside
  487.      * @param oGapHeight the size in pixels around the outside
  488.      */
  489.     public void setGapSizes(int iGapWidth, int iGapHeight, int oGapWidth, int oGapHeight)
  490.     {
  491.         this.iGapWidth  = iGapWidth;
  492.         this.iGapHeight = iGapHeight;
  493.         this.oGapWidth  = oGapWidth;
  494.         this.oGapHeight = oGapHeight;
  495.         adjustOGapBdr();
  496.         propagateChanges();
  497.         invalidate();
  498.     }
  499.  
  500.     /**
  501.      * Sets the size of the gap between panes and around the
  502.      * outside.
  503.      * @param iBdrSize the size in pixels between panes
  504.      * @param oBdrSize the size in pixels around the outside
  505.      */
  506.     public void setBdrSizes(int iBdrSize, int oBdrSize)
  507.     {
  508.         this.iBdrSize = iBdrSize;
  509.         this.oBdrSize = oBdrSize;
  510.         adjustOGapBdr();
  511.         propagateChanges();
  512.         invalidate();
  513.     }
  514.  
  515.     /**
  516.      * Sets the size of the border between panes and around the
  517.      * outside.
  518.      * @param bdrSize the size in pixels
  519.      */
  520.     public void setBdrSizes(int bdrSize)
  521.     {
  522.         this.iBdrSize  = bdrSize;
  523.         this.oBdrSize  = bdrSize;
  524.         adjustOGapBdr();
  525.         propagateChanges();
  526.         invalidate();
  527.     }
  528.  
  529.     /**
  530.      * Gets the color of the gap between panes and around
  531.      * the outside.
  532.      * @return the current gap color
  533.      * @see setGapColor
  534.      */
  535.     public Color gapColor()
  536.     {
  537.         return this.gapColor;
  538.     }
  539.  
  540.     /**
  541.      * Sets the "enforce minimum dimension" mode.
  542.      * @param theFlag if true, prevents dragging the split between panes
  543.      * from making a panel smaller than the minimum size of its component.
  544.      * @see #getEnforceMinDim
  545.      */
  546.     public void setEnforceMinDim(boolean theFlag)
  547.     {
  548.         enforceMinDim = theFlag;
  549.         propagateChanges();
  550.     }
  551.  
  552.     /**
  553.      * Gets the current "enforce minimum dimension" mode.
  554.      * @return the current mode
  555.      * @see #setEnforceMinDim
  556.      */
  557.     public boolean getEnforceMinDim()
  558.     {
  559.         return enforceMinDim;
  560.     }
  561.  
  562.     /**
  563.      * Sets the "resize propagation" mode.
  564.      * Set this to false to prevent the automatic resizing of SplitterPanel
  565.      * panes from also calling resize() for the component that you add.
  566.      * The default behavior propagates the resizing effect of dragging the
  567.      * split between panes by calling move and resize for the panels that have
  568.      * been added to those panes.  Clearing this introduces a clipping effect,
  569.      * rather than a scaling effect.
  570.      * @param theFlag if true, resize propagation is enabled; if false,
  571.      * resize propagation is disabled
  572.      * @see #getPropResize
  573.      */
  574.     public void setPropResize(boolean theFlag)
  575.     {
  576.         //Controls whether reshapes are propagated into added components
  577.         propResize = theFlag;
  578.         propagateChanges();
  579.     }
  580.  
  581.     /**
  582.      * Gets the current "resize propagation" mode.
  583.      * @return the current "resize propagation" mode
  584.      * @see #setPropResize
  585.      */
  586.     public boolean getPropResize()
  587.     {
  588.         return propResize;
  589.     }
  590.  
  591.     /**
  592.      * Gets the type of split for this SplitterPanel.
  593.      * @return splitType SPLIT_VER or SPLIT_HOR
  594.      * @see #SPLIT_VER
  595.      * @see #SPLIT_HOR
  596.      */
  597.     public int getSplitType()
  598.     {
  599.         SplitterPanel targetSP = this;
  600.         if (isOuter) targetSP = this.innerSP;
  601.         return targetSP.splitType;
  602.     }
  603.  
  604.     /**
  605.      * Gets a pane within a SplitterPanel.
  606.      * @param n pane number (1 for first pane, or 2 for second
  607.      * pane)
  608.      * @return the pane, or null if none
  609.      */
  610.     public SplitterPanel getSubPanel(int n)
  611.     {
  612.         SplitterPanel targetSP = this;
  613.  
  614.         if (isOuter)
  615.             targetSP = this.innerSP;
  616.  
  617.         if (n == 1)
  618.             return targetSP.sub1;
  619.  
  620.         if (n == 2)
  621.             return targetSP.sub2;
  622.  
  623.         return null;
  624.     }
  625.  
  626.     /**
  627.      * Gets a pane within a SplitterPanel of specified type.
  628.      * @param n pane number (1 for first pane, or 2 for second
  629.      * pane)
  630.      * @param theSplitType specifies the type of split desired
  631.      * (SPLIT_VER or SPLIT_HOR)
  632.      * @return the pane, or null if none of specified
  633.      * type
  634.      * @see #SPLIT_VER
  635.      * @see #SPLIT_HOR
  636.      */
  637.     public SplitterPanel getSubPanel(int n, int theSplitType)
  638.     {
  639.         if (getSplitType() == theSplitType)
  640.             return getSubPanel(n);
  641.  
  642.         return null;
  643.     }
  644.  
  645.     /**
  646.      * Gets a pane within a doubly split SplitterPanel with
  647.      * specified split types.
  648.      * @param n1 pane number (1 for first pane, or 2 for second pane)
  649.      * @param theSplitType1 specifies the type of split desired
  650.      * (SPLIT_VER or SPLIT_HOR)
  651.      * @param n2 pane number (1 for first pane, or 2 for second pane)
  652.      * @param theSplitType2 specifies the type of split desired
  653.      * (SPLIT_VER or SPLIT_HOR)
  654.      * @return the pane, or null if none of specified
  655.      * type
  656.      * @see #SPLIT_VER
  657.      * @see #SPLIT_HOR
  658.      */
  659.     public SplitterPanel getSub2Panel(int n1, int theSplitType1, int n2, int theSplitType2)
  660.     {
  661.         SplitterPanel theSP;
  662.  
  663.         theSP = getSubPanel(n1, theSplitType1);
  664.         if (theSP != null)
  665.             return theSP.getSubPanel(n2, theSplitType2);
  666.  
  667.         return null;
  668.     }
  669.  
  670.     /**
  671.      * Gets top panel of a horizontally split SplitterPanel.
  672.      * @return the pane, or null if none of specified
  673.      * type
  674.      */
  675.     public SplitterPanel getTopPanel()
  676.     {
  677.         return getSubPanel(1, SPLIT_HOR);
  678.     }
  679.  
  680.     /**
  681.      * Gets the bottom panel.
  682.      * @return the pane, or null if none of specified
  683.      * type
  684.      */
  685.     public SplitterPanel getBottomPanel()
  686.     {
  687.         return getSubPanel(2, SPLIT_HOR);
  688.     }
  689.  
  690.     /**
  691.      * Gets the left panel.
  692.      * @return the pane, or null if none of specified
  693.      * type
  694.      */
  695.     public SplitterPanel getLeftPanel()
  696.     {
  697.         return getSubPanel(1, SPLIT_VER);
  698.     }
  699.  
  700.     /**
  701.      * Gets the right panel.
  702.      * @return the pane, or null if none of specified
  703.      * type
  704.      */
  705.     public SplitterPanel getRightPanel()
  706.     {
  707.         return getSubPanel(2, SPLIT_VER);
  708.     }
  709.  
  710.     /**
  711.      * Gets the top left panel.
  712.      * @return the pane, or null if none of specified
  713.      * type
  714.      */
  715.     public SplitterPanel getTopLeftPanel()
  716.     {
  717.         if (getSplitType() == SPLIT_HOR)
  718.             return getSub2Panel(1, SPLIT_HOR, 1, SPLIT_VER);
  719.  
  720.         return getSub2Panel(1, SPLIT_VER, 1, SPLIT_HOR);
  721.     }
  722.  
  723.     /**
  724.      * Gets the top right panel.
  725.      * @return the pane, or null if none of specified
  726.      * type
  727.      */
  728.     public SplitterPanel getTopRightPanel()
  729.     {
  730.         if (getSplitType() == SPLIT_HOR)
  731.             return getSub2Panel(1, SPLIT_HOR, 2, SPLIT_VER);
  732.  
  733.         return getSub2Panel(2, SPLIT_VER, 1, SPLIT_HOR);
  734.     }
  735.  
  736.     /**
  737.      * Gets the bottom left panel.
  738.      * @return the pane, or null if none of specified
  739.      * type
  740.      */
  741.     public SplitterPanel getBottomLeftPanel()
  742.     {
  743.         if (getSplitType() == SPLIT_HOR)
  744.             return getSub2Panel(2, SPLIT_HOR, 1, SPLIT_VER);
  745.  
  746.         return getSub2Panel(1, SPLIT_VER, 2, SPLIT_HOR);
  747.     }
  748.  
  749.     /**
  750.      * Gets the bottom right panel.
  751.      * @return the pane, or null if none of specified
  752.      * type
  753.      */
  754.     public SplitterPanel getBottomRightPanel()
  755.     {
  756.         if (getSplitType() == SPLIT_HOR)
  757.             return getSub2Panel(2, SPLIT_HOR, 2, SPLIT_VER);
  758.  
  759.         return getSub2Panel(2, SPLIT_VER, 2, SPLIT_HOR);
  760.     }
  761.  
  762.  
  763.     //--------------------------------------------------
  764.     // event methods
  765.     //--------------------------------------------------
  766.  
  767.  
  768.     /**
  769.      * This standard routine is called by the Java AWT to handle events.
  770.      * Do NOT override this method.
  771.      * @param evt the event to handle
  772.      * @return true if the event was handled an no further action is needed,
  773.      * false to pass the event to this component's parent
  774.      */
  775.     public boolean handleEvent(Event evt)
  776.     {
  777.         if ((evt.target == this) && isOuter)
  778.         {
  779.             return oGapThis(evt);
  780.         }
  781.  
  782.         switch (evt.id)
  783.         {
  784.             case Event.MOUSE_MOVE:
  785.             {
  786.                 if ((evt.target == this) && (splitType == SPLIT_HOR) && inGap1(evt.x, evt.y))
  787.                 {
  788.                     setCursor(moveSplitCursor);
  789.                     return true;
  790.                 }
  791.                 else if ((evt.target == this) && (splitType == SPLIT_VER) && inGap1(evt.x, evt.y))
  792.                 {
  793.                     setCursor(moveSplitCursor);
  794.                     return true;
  795.                 }
  796.                 else
  797.                 {
  798.                     //if (!doMoveSplit && !inGap(evt)) resetCursor();
  799.                     return true;
  800.                 }
  801.                 
  802.             }
  803.  
  804.             case Event.MOUSE_DOWN:
  805.             {   
  806.                 if ((evt.target == this) && (splitType == SPLIT_HOR) && outerSP.cursorChanged)
  807.                 {
  808.                     doMoveSplit = true;
  809.                     moveFromX = evt.x;
  810.                     moveFromY = evt.y;
  811.                     return true;
  812.                 }
  813.                 else if ((evt.target == this) && (splitType == SPLIT_VER) && outerSP.cursorChanged)
  814.                 {
  815.                     doMoveSplit = true;
  816.                     moveFromX = evt.x;
  817.                     moveFromY = evt.y;
  818.                     return true;
  819.                 }
  820.                 
  821.                 if (outerSP.cursorChanged)
  822.                 {
  823.                     Point p = location();
  824.                     getParent().postEvent(new Event(cursorCh, evt.when, evt.id, p.x + evt.x, p.y + evt.y, evt.key, evt.modifiers, evt.arg));
  825.                     return true;
  826.                 }
  827.                 
  828.             }
  829.  
  830.             case Event.MOUSE_DRAG:
  831.             {
  832.                 if (doMoveSplit == true)
  833.                 {
  834.                     setCursor(moveSplitCursor);
  835.                     return true;
  836.                 }
  837.             }
  838.  
  839.             case Event.MOUSE_UP:
  840.             {
  841.                 //Important -- Do NOT check that this is the target for mouse up
  842.                 if (doMoveSplit == true)
  843.                 {
  844.                     moveSplit(evt.x - moveFromX, evt.y - moveFromY);
  845.                     doMoveSplit = false;
  846.                     return true;
  847.                 }
  848.             }
  849.  
  850.         }
  851.  
  852.         return super.handleEvent(evt);
  853.     }
  854.  
  855.  
  856.     //--------------------------------------------------
  857.     // class methods
  858.     //--------------------------------------------------
  859.  
  860.  
  861.     //--------------------------------------------------
  862.     // member methods
  863.     //--------------------------------------------------
  864.  
  865.     /**
  866.      * Gets the current inside gap width.
  867.      * @return size in pixels between panes
  868.      */
  869.     public int iGapWidth()
  870.     {
  871.         return this.iGapWidth;
  872.     }
  873.  
  874.     /**
  875.      * Gets the current inside gap height.
  876.      * @return size in pixels between panes
  877.      */
  878.     public int iGapHeight()
  879.     {
  880.         return this.iGapHeight;
  881.     }
  882.  
  883.     /**
  884.      * Gets the current inside gap width.
  885.      * @return size in pixels around
  886.      */
  887.     public int oGapWidth()
  888.     {
  889.         return this.oGapWidth;
  890.     }
  891.  
  892.     /**
  893.      * Gets the current outside gap height.
  894.      * @return size in pixels around outside
  895.      */
  896.     public int oGapHeight()
  897.     {
  898.         return this.oGapHeight;
  899.     }
  900.  
  901.     /**
  902.      * Gets the current pane border size.
  903.      * @return size in pixels around panes
  904.      */
  905.     public int iBdrSize()
  906.     {
  907.         return this.iBdrSize;
  908.     }
  909.  
  910.     /**
  911.      * Gets the current outside border size.
  912.      * @return size in pixels around outside
  913.      */
  914.     public int oBdrSize()
  915.     {
  916.         return this.oBdrSize;
  917.     }
  918.  
  919.     private int optSize(int total, int _gap, int _min1, int _min2, int _pref1, int _pref2)
  920.     {
  921.         int diff;
  922.         float scale;
  923.         int gap;
  924.         int min1;
  925.         int min2;
  926.         int pref1;
  927.         int pref2;
  928.  
  929.         gap  = Math.max(_gap, 0);
  930.         min1 = Math.max(_min1,  1);
  931.         min2 = Math.max(_min2,  1);
  932.         pref1 = Math.max(_pref1,  min1);
  933.         pref2 = Math.max(_pref2,  min2);
  934.  
  935.         diff = total - (pref1 + pref2 + gap);
  936.  
  937.         if (diff >= 0)
  938.         {
  939.             scale = (float)pref1/(float)(pref1 + pref2);
  940.             return pref1 + (int)(diff*scale);
  941.         }
  942.  
  943.         diff = total - (min1 + min2 + gap);
  944.         if (diff >= 0)
  945.         {
  946.             scale = (float)pref1/(float)(pref1 + pref2);
  947.             return min1 + (int)(diff*scale);
  948.         }
  949.  
  950.         if (total > gap)
  951.         {
  952.             scale = (float)min1/(float)(min1 + min2);
  953.             return min1 + (int)(diff*scale);
  954.         }
  955.  
  956.         return total;
  957.     }
  958.  
  959.     /**
  960.      * This standard routine is called by the Java AWT to handle the laying
  961.      * out of components within other components.
  962.      */
  963.     public synchronized void layout() {
  964.       placeComponents();
  965.     }
  966.     private void placeComponents()
  967.     {
  968.         Dimension prefDim1;
  969.         Dimension prefDim2;
  970.         Dimension minDim1;
  971.         Dimension minDim2;
  972.  
  973.         int sub1X;
  974.         int sub1Y;
  975.         int sub2X;
  976.         int sub2Y;
  977.         int sub1Width;
  978.         int sub1Height;
  979.         int sub2Width;
  980.         int sub2Height;
  981.  
  982.         Rectangle rect = new Rectangle(curLoc.x, curLoc.y, curDim.width, curDim.height);
  983.  
  984.         if (isOuter)
  985.         {
  986.             sub1X = oGapWidth  + oBdrSize;
  987.             sub1Y = oGapHeight + oBdrSize;
  988.             sub1Width  = rect.width  - ((2 * oGapWidth  + oBdrSize +1 ) );
  989.             sub1Height = rect.height - ((2 * oGapHeight + oBdrSize + 1) );
  990.             innerSP.reshape(sub1X, sub1Y, sub1Width, sub1Height);
  991.         }
  992.         else
  993.         {
  994.             if (sub1 == null)
  995.             {
  996.                 minDim1  = new Dimension(1, 1);
  997.                 prefDim1 = new Dimension(1, 1);
  998.             }
  999.             else
  1000.             {
  1001.                 minDim1  = sub1.minimumSize();
  1002.                 prefDim1 = sub1.preferredSize();
  1003.             }
  1004.  
  1005.             if (sub2 == null)
  1006.             {
  1007.                 minDim2  = new Dimension(1, 1);
  1008.                 prefDim2 = new Dimension(1, 1);
  1009.             }
  1010.             else
  1011.             {
  1012.                 minDim2  = sub2.minimumSize();
  1013.                 prefDim2 = sub2.preferredSize();
  1014.             }
  1015.  
  1016.             dimChanged = false;
  1017.  
  1018.             switch (splitType)
  1019.             {
  1020.                 case SPLIT_NONE:
  1021.                 {
  1022.                     if (spComponent != null)
  1023.                     {
  1024.                         sub1X = iBdrSize;
  1025.                         sub1Y = iBdrSize;
  1026.                         sub1Width  = rect.width  - (2 * iBdrSize);
  1027.                         sub1Height = rect.height - (2 * iBdrSize);
  1028.                         if (sub1Width < 0)
  1029.                             sub1Width = 0;
  1030.                         if (sub1Height < 0)
  1031.                             sub1Height = 0;
  1032.                         if (propResize) spComponent.reshape(sub1X, sub1Y, sub1Width, sub1Height);
  1033.                         else spComponent.move(sub1X, sub1Y);
  1034.                         spComponent.layout();
  1035.                         spComponent.invalidate();
  1036.                         spComponent.validate();
  1037.             try {
  1038.                             spComponent.repaint();
  1039.             } catch(Exception e) {
  1040.                      repaint();
  1041.             }
  1042.                     }
  1043.  
  1044.                     return;
  1045.                 }
  1046.  
  1047.                 case SPLIT_VER:
  1048.                 {
  1049.                     sub1X = 0;
  1050.                     sub1Y = 0;
  1051.                     sub1Width = optSize(rect.width, iGapWidth, minDim1.width, minDim2.width, prefDim1.width, prefDim2.width);
  1052.                     sub1Height = rect.height;
  1053.  
  1054.                     sub2X = sub1Width + iGapWidth;
  1055.                     sub2Y = 0;
  1056.                     sub2Width = rect.width - sub2X;
  1057.                     sub2Height = rect.height;
  1058.  
  1059.                     break;
  1060.                 }
  1061.  
  1062.                 case SPLIT_HOR:
  1063.                 {
  1064.                     sub1X = 0;
  1065.                     sub1Y = 0;
  1066.                     sub1Width = rect.width;
  1067.                     sub1Height = optSize(rect.height, iGapHeight, minDim1.height, minDim2.height, prefDim1.height, prefDim2.height);
  1068.  
  1069.                     sub2X = 0;
  1070.                     sub2Y = sub1Height + iGapHeight;
  1071.                     sub2Width = rect.width;
  1072.                     sub2Height = rect.height - sub2Y;
  1073.  
  1074.                     break;
  1075.                 }
  1076.  
  1077.                 default:
  1078.                     return;
  1079.  
  1080.             }
  1081.  
  1082.             if (heightOnly)
  1083.             {
  1084.                 heightOnly = false;
  1085.                 sub1.reshapeHeight(sub1Y, sub1Height);
  1086.                 sub2.reshapeHeight(sub2Y, sub2Height);
  1087.             }
  1088.             else if (widthOnly)
  1089.             {
  1090.                 widthOnly = false;
  1091.                 sub1.reshapeWidth(sub1X, sub1Width);
  1092.                 sub2.reshapeWidth(sub2X, sub2Width);
  1093.             }
  1094.             else
  1095.             {
  1096.                 sub1.reshape(sub1X, sub1Y, sub1Width, sub1Height);
  1097.                 sub2.reshape(sub2X, sub2Y, sub2Width, sub2Height);
  1098.             }
  1099.  
  1100.             sub1.invalidate();
  1101.             sub1.validate();
  1102.             sub1.repaint();
  1103.             sub2.invalidate();
  1104.             sub2.validate();
  1105.             sub2.repaint();
  1106.         }
  1107.     }
  1108.  
  1109.     /**
  1110.      * Moves the location of the gap between panes.
  1111.      * @param spX specifies relative movement in pixels along X axis
  1112.      * @param spY specifies relative movement in pixels along Y axis
  1113.      */
  1114.     public void moveSplit(int spX, int spY)
  1115.     {
  1116.         Rectangle cur1;
  1117.         Rectangle cur2;
  1118.         Dimension min1;
  1119.         Dimension min2;
  1120.  
  1121.         int delta;
  1122.         int newX1;
  1123.         int newY1;
  1124.         int newWidth1;
  1125.         int newHeight1;
  1126.         int newX2;
  1127.         int newY2;
  1128.         int newWidth2;
  1129.         int newHeight2;
  1130.  
  1131.         if (isOuter)
  1132.         {
  1133.             innerSP.moveSplit(spX, spY);
  1134.             return;
  1135.         }
  1136.         else
  1137.         {
  1138.             min1 = sub1.minimumSize();
  1139.             min2 = sub2.minimumSize();
  1140.             cur1 = new Rectangle(sub1.curLoc.x, sub1.curLoc.y, sub1.curDim.width, sub1.curDim.height);
  1141.             cur2 = new Rectangle(sub2.curLoc.x, sub2.curLoc.y, sub2.curDim.width, sub2.curDim.height);
  1142.             newX1 = cur1.x;
  1143.             newY1 = cur1.y;
  1144.  
  1145.             if (splitType == SPLIT_HOR)
  1146.             {
  1147.                 if (spY == 0) return;
  1148.                 if (spY > 0)
  1149.                 {
  1150.                     if (enforceMinDim)
  1151.                     {
  1152.                          newHeight2 = Math.max(cur2.height - spY, min2.height);
  1153.                     }
  1154.                     else
  1155.                     {
  1156.                          newHeight2 = Math.max(cur2.height - spY, 2*iBdrSize);
  1157.                     }
  1158.                     newHeight1 = cur1.height + cur2.height - newHeight2;
  1159.                 }
  1160.                 else
  1161.                 {
  1162.                     if (enforceMinDim)
  1163.                     {
  1164.                          newHeight1 = Math.max(cur1.height + spY, min1.height);
  1165.                     }
  1166.                     else
  1167.                     {
  1168.                          newHeight1 = Math.max(cur1.height + spY, 2*iBdrSize);
  1169.                     }
  1170.                     newHeight2 = cur2.height + cur1.height - newHeight1;
  1171.                 }
  1172.                 newWidth1 = cur1.width;
  1173.                 newWidth2 = cur2.width;
  1174.                 newX2 = cur2.x;
  1175.                 newY2 = cur2.y - cur1.height + newHeight1;
  1176.                 sub1.reshapeHeight(newY1, newHeight1);
  1177.                 sub2.reshapeHeight(newY2, newHeight2);
  1178.             }
  1179.  
  1180.             if (splitType == SPLIT_VER)
  1181.             {
  1182.                 if (spX == 0) return;
  1183.                 if (spX > 0)
  1184.                 {
  1185.                     if (enforceMinDim)
  1186.                     {
  1187.                          newWidth2 = Math.max(cur2.width - spX, min2.width);
  1188.                     }
  1189.                     else
  1190.                     {
  1191.                          newWidth2 = Math.max(cur2.width - spX, 2*iBdrSize);
  1192.                     }
  1193.                     newWidth1 = cur1.width + cur2.width - newWidth2;
  1194.  
  1195.                 }
  1196.                 else
  1197.                 {
  1198.                     if (enforceMinDim)
  1199.                     {
  1200.                          newWidth1 = Math.max(cur1.width + spX, min1.width);
  1201.                     }
  1202.                     else
  1203.                     {
  1204.                          newWidth1 = Math.max(cur1.width + spX, 1*iBdrSize);
  1205.                     }
  1206.                     newWidth2 = cur2.width + cur1.width - newWidth1;
  1207.  
  1208.                 }
  1209.                 newHeight1 = cur1.height;
  1210.                 newHeight2 = cur2.height;
  1211.                 newY2 = cur2.y;
  1212.                 newX2 = cur2.x - cur1.width + newWidth1;
  1213.                 sub1.reshapeWidth(newX1, newWidth1);
  1214.                 sub2.reshapeWidth(newX2, newWidth2);
  1215.             }
  1216.  
  1217.             sub1.invalidate();
  1218.             sub1.validate();
  1219.             sub1.repaint();
  1220.             sub2.invalidate();
  1221.             sub2.validate();
  1222.             sub2.repaint();
  1223.         }
  1224.     }
  1225.  
  1226.     /**
  1227.      * This standard routine is called by the Java AWT (repaint()) to handle
  1228.      * the repainting of this component on the screen. 
  1229.      * @param g the Graphics object
  1230.      */
  1231.     public void update(Graphics g)
  1232.     {
  1233.         paint(g);
  1234.     }
  1235.  
  1236.     private void draw3DBdr(Graphics g, int x, int y, int width, int height, int bdrSize, Color c, boolean raised)
  1237.     {
  1238.         int i;
  1239.  
  1240.         if (bdrSize < 0)
  1241.             return;
  1242.  
  1243.         g.setColor(use3dBdr ? c : c.darker());
  1244.  
  1245.         for (i = 0; i < bdrSize; i++)
  1246.         {
  1247.             if (use3dBdr) g.draw3DRect(x + i, y + i, width - 2*i, height - 2*i, raised);
  1248.             else g.drawRect(x + i, y + i, width - 2*i, height - 2*i);
  1249.         }
  1250.     }
  1251.  
  1252.     /**
  1253.      * This standard routine is called by the Java AWT to handle painting this
  1254.      * component. It paints this component using the given graphics context.
  1255.      * Overriding this method is not advised.
  1256.      * @param g the graphics context used for painting
  1257.      */
  1258.     public void paint(Graphics g)
  1259.     {
  1260.         Color bgColor;
  1261.         Color fgColor;
  1262.  
  1263.         if (dimChanged)
  1264.             placeComponents();
  1265.  
  1266.         Dimension d = size();
  1267.  
  1268.         bgColor = getBackground();
  1269.         g.setColor(bgColor);
  1270.  
  1271.         if (isOuter)
  1272.         {
  1273.             g.setColor(gapColor);
  1274.             g.fillRect(0, 0, d.width, d.height);
  1275.             draw3DBdr(g, 0, 0, d.width-1, d.height-1, oBdrSize, gapColor, true);
  1276.         }
  1277.         else if (splitType == SPLIT_NONE)
  1278.         {
  1279.             g.setColor(bgColor);
  1280.             g.fillRect(0, 0, d.width, d.height );
  1281.             draw3DBdr(g, 0, 0, d.width-1, d.height-1, iBdrSize, gapColor, false);
  1282.         }
  1283.         else
  1284.         {
  1285.             g.setColor(gapColor);
  1286.             g.fillRect(0, 0, d.width, d.height );
  1287.         }
  1288.  
  1289.         super.paint(g);
  1290.     }
  1291.  
  1292.  
  1293.     /**
  1294.      * Gets the component in a SplitterPanel.
  1295.      * @return the component in the SplitterPanel
  1296.      */
  1297.     public Component getComponent()
  1298.     {
  1299.         if (isOuter)
  1300.             return innerSP.getComponent();
  1301.  
  1302.         return spComponent;
  1303.     }
  1304.  
  1305.     /**
  1306.      * This standard Container routine gets an array of components in this
  1307.      * Container. It is NOT supported.
  1308.      * @return null
  1309.      */
  1310.     public Component[] getComponents()
  1311.     {
  1312.         return null;
  1313.     }
  1314.  
  1315.     private void propagateChanges()
  1316.     {
  1317.         if (innerSP != null)
  1318.         {
  1319.             propagateChangesSP(innerSP);
  1320.             innerSP.propagateChanges();
  1321.         }
  1322.  
  1323.         if (sub1 != null)
  1324.         {
  1325.             propagateChangesSP(sub1);
  1326.             sub1.propagateChanges();
  1327.         }
  1328.  
  1329.         if (sub2 != null)
  1330.         {
  1331.             propagateChangesSP(sub2);
  1332.             sub2.propagateChanges();
  1333.         }
  1334.     }
  1335.  
  1336.     private void propagateChangesSP(SplitterPanel spTarget)
  1337.     {
  1338.         if ((spTarget.oGapWidth  != this.oGapWidth) ||
  1339.             (spTarget.iGapWidth  != this.iGapWidth) ||
  1340.             (spTarget.oGapHeight != this.oGapWidth) ||
  1341.             (spTarget.iGapHeight != this.iGapHeight) ||
  1342.             (spTarget.iBdrSize   != this.iBdrSize) ||
  1343.             (spTarget.oBdrSize   != this.oBdrSize) ||
  1344.             (spTarget.use3dBdr   != this.use3dBdr))
  1345.         {
  1346.             this.dimChanged     = true;
  1347.             spTarget.dimChanged = true;
  1348.         }
  1349.  
  1350.         spTarget.oGapWidth  = this.oGapWidth;
  1351.         spTarget.iGapWidth  = this.iGapWidth;
  1352.         spTarget.oGapHeight = this.oGapWidth;
  1353.         spTarget.iGapHeight = this.iGapHeight;
  1354.         spTarget.iBdrSize   = this.iBdrSize;
  1355.         spTarget.oBdrSize   = this.oBdrSize;
  1356.         spTarget.gapColor   = this.gapColor;
  1357.         spTarget.enforceMinDim   = this.enforceMinDim;
  1358.         spTarget.moveSplitCursor = this.moveSplitCursor;
  1359.         spTarget.propResize = this.propResize;
  1360.         spTarget.use3dBdr   = this.use3dBdr;
  1361.     }
  1362.  
  1363.     private Dimension maxDimOf(Dimension dim1, Dimension dim2)
  1364.     {
  1365.         return new Dimension(Math.max(dim1.width, dim2.width), Math.max(dim1.height, dim2.height));
  1366.     }
  1367.  
  1368.     /**
  1369.      * Returns the recommended dimensions to properly display this component.
  1370.      */
  1371.     public Dimension preferredSize()
  1372.     {
  1373.         Dimension theDim;
  1374.  
  1375.         if (isOuter)
  1376.         {
  1377.             theDim = new Dimension(innerSP.preferredSize());
  1378.             theDim.width  += 2*(oGapWidth  + oBdrSize);
  1379.             theDim.height += 2*(oGapHeight + oBdrSize);
  1380.         }
  1381.         else
  1382.         {
  1383.             if (splitType == SPLIT_NONE)
  1384.             {
  1385.                 if (spComponent == null)
  1386.                 {
  1387.                     theDim = new Dimension(0, 0);
  1388.                 }
  1389.                 else
  1390.                 {
  1391.                     theDim = new Dimension(spComponent.preferredSize());
  1392.                 }
  1393.                 theDim.width  += 2*(iBdrSize);
  1394.                 theDim.height += 2*(iBdrSize);
  1395.             }
  1396.             else
  1397.             {
  1398.                 Dimension theDim1;
  1399.                 Dimension theDim2;
  1400.  
  1401.                 theDim1 = sub1.preferredSize();
  1402.                 theDim2 = sub2.preferredSize();
  1403.  
  1404.                 if (splitType == SPLIT_HOR)
  1405.                 {
  1406.                     theDim = new Dimension(theDim1.width, theDim1.height + theDim2.height);
  1407.                     theDim.height += iGapHeight;
  1408.                 }
  1409.                 else
  1410.                 {
  1411.                     theDim = new Dimension(theDim1.width + theDim1.width, theDim1.height);
  1412.                     theDim.width  += iGapWidth;
  1413.                 }
  1414.             }
  1415.         }
  1416.  
  1417.         return maxDimOf(prefDim, theDim);
  1418.     }
  1419.  
  1420.     /**
  1421.      * Returns the minimum dimensions to properly display this component.
  1422.      */
  1423.     public Dimension minimumSize()
  1424.     {
  1425.         Dimension theDim;
  1426.  
  1427.         if (isOuter)
  1428.         {
  1429.             theDim = new Dimension(innerSP.minimumSize());
  1430.             theDim.width  += 2*(oGapWidth  + oBdrSize);
  1431.             theDim.height += 2*(oGapHeight + oBdrSize);
  1432.         }
  1433.         else
  1434.         {
  1435.             if (splitType == SPLIT_NONE)
  1436.             {
  1437.                 if (spComponent == null)
  1438.                 {
  1439.                     theDim = new Dimension(0, 0);
  1440.                 }
  1441.                 else
  1442.                 {
  1443.                     theDim = new Dimension(spComponent.minimumSize());
  1444.                 }
  1445.                 theDim.width  += 2*(iBdrSize);
  1446.                 theDim.height += 2*(iBdrSize);
  1447.             }
  1448.             else
  1449.             {
  1450.                 Dimension theDim1;
  1451.                 Dimension theDim2;
  1452.  
  1453.                 theDim1 = sub1.minimumSize();
  1454.                 theDim2 = sub2.minimumSize();
  1455.  
  1456.                 if (splitType == SPLIT_HOR)
  1457.                 {
  1458.                     theDim = new Dimension(theDim1.width, theDim1.height + theDim2.height);
  1459.                     theDim.height += iGapHeight;
  1460.                 }
  1461.                 else
  1462.                 {
  1463.                     theDim = new Dimension(theDim1.width + theDim1.width, theDim1.height);
  1464.                     theDim.width  += iGapWidth;
  1465.                 }
  1466.             }
  1467.         }
  1468.  
  1469.         return maxDimOf(minDim, theDim);
  1470.     }
  1471.  
  1472.     /**
  1473.      * Sets the preferred size of a SplitterPanel.  This will
  1474.      * override the calculated size.
  1475.      * @param theDim the dimension of the preferred size
  1476.      */
  1477.     public void setPreferredSize(Dimension theDim)
  1478.     {
  1479.         prefDim.width  = theDim.width;
  1480.         prefDim.height = theDim.height;
  1481.         //Must ensure that preferred size is as big as minimum size
  1482.         prefDim = maxDimOf(theDim, prefDim);
  1483.         dimChanged = true;
  1484.     }
  1485.  
  1486.     /**
  1487.      * Sets the minimum size of a SplitterPanel.  This will override
  1488.      * the calculated size.
  1489.      * @param theDim the dimension of the minimum size
  1490.      */
  1491.     public void setMinimumSize(Dimension theDim)
  1492.     {
  1493.         minDim.width  = theDim.width;
  1494.         minDim.height = theDim.height;
  1495.         prefDim = maxDimOf(theDim, prefDim);
  1496.         dimChanged = true;
  1497.     }
  1498.  
  1499.     /**
  1500.      * This standard Java AWT routine is called to move and/or resize this component.
  1501.      * @param x the new position, x coordinate
  1502.      * @param y the new position, y coordinate
  1503.      * @param width the new width
  1504.      * @param height the new height
  1505.      * @see #reshapeHeight
  1506.      * @see #reshapeWidth
  1507.      */
  1508.     public synchronized void reshape (int x, int y, int width, int height) {
  1509.         super.reshape(x, y, width, height);
  1510.         if ((curDim.width  != width) || (curDim.height != height) ||
  1511.             (curLoc.x != x) || (curLoc.y != y))
  1512.         {
  1513.             dimChanged = true;
  1514.             curDim.width  = width;
  1515.             curDim.height = height;
  1516.             curLoc.x      = x;
  1517.             curLoc.y      = y;
  1518.         }
  1519.     }
  1520.  
  1521.     /**
  1522.      * Reshape width only to prevent height adjustments when layout is computed.
  1523.      * @param x new x position
  1524.      * @param width new width
  1525.      * @see #reshapeHeight
  1526.      * @see #reshape
  1527.      */
  1528.     public synchronized void reshapeWidth(int x, int width) {
  1529.         Rectangle rect = new Rectangle(curLoc.x, curLoc.y, curDim.width, curDim.height);
  1530.  
  1531.         if (curDim.width  != width)
  1532.         {
  1533.             dimChanged = true;
  1534.             widthOnly = true;
  1535.             curDim.width  = width;
  1536.         }
  1537.         reshape(x, rect.y, width, rect.height);
  1538.     }
  1539.  
  1540.     /**
  1541.      * Reshape height only to prevent width adjustments when layout is computed.
  1542.      * @param y new y position
  1543.      * @param height new height
  1544.      * @see #reshapeWidth
  1545.      * @see #reshape
  1546.      */
  1547.     public synchronized void reshapeHeight(int y, int height) {
  1548.         Rectangle rect = new Rectangle(curLoc.x, curLoc.y, curDim.width, curDim.height);
  1549.  
  1550.         if (curDim.height != height)
  1551.         {
  1552.             dimChanged = true;
  1553.             heightOnly = true;
  1554.             curDim.height = height;
  1555.         }
  1556.         reshape(rect.x, y, rect.width, height);
  1557.     }
  1558.  
  1559.     /**
  1560.      * Add a single component to the SplitterPanel.
  1561.      * This method supports addition of one component at a time.
  1562.      * If there is already a component present, it is replaced
  1563.      * by the given component.
  1564.      * @param comp the component to add
  1565.      * @param pos the position
  1566.      * @return the added component, if successful
  1567.      * @see #remove
  1568.      **/
  1569.     public synchronized Component add(Component comp, int pos)
  1570.     {
  1571.         if (comp == null)
  1572.             return null;
  1573.  
  1574.         if (isOuter)
  1575.             return innerSP.add(comp, pos);
  1576.  
  1577.         if (spComponent != null)
  1578.             super.remove(spComponent);
  1579.  
  1580.         spComponent = super.add(comp, -1);
  1581.     dimChanged=true;
  1582.  
  1583.         return spComponent;
  1584.     }
  1585.  
  1586.     /**
  1587.      * Remove a component from the SplitterPanel.
  1588.      * @param comp the component to remove
  1589.      * @see #add
  1590.      */
  1591.     public synchronized void remove(Component comp)
  1592.     {
  1593.         if (isOuter)
  1594.         {
  1595.             innerSP.remove(comp);
  1596.         }
  1597.         else
  1598.         {
  1599.             if (comp == spComponent)
  1600.             {
  1601.                 spComponent = null;
  1602.                 super.remove(comp);
  1603.             }
  1604.             else
  1605.             {
  1606.                 if (sub1 != null)
  1607.                     sub1.remove(comp);
  1608.  
  1609.                 if (sub2 != null)
  1610.                     sub2.remove(comp);
  1611.             }
  1612.         }
  1613.     }
  1614.  
  1615.     /**
  1616.      * Remove all components from the SplitterPanel.
  1617.      * Split panes are preserved.
  1618.      */
  1619.     public synchronized void removeAll()
  1620.     {
  1621.         if (isOuter)
  1622.         {
  1623.             innerSP.removeAll();
  1624.         }
  1625.  
  1626.         else
  1627.         {
  1628.             super.removeAll();
  1629.  
  1630.             if (sub1 != null)
  1631.             {
  1632.                 super.add(sub1, -1);
  1633.                 sub1.removeAll();
  1634.             }
  1635.  
  1636.             if (sub2 != null)
  1637.             {
  1638.                 super.add(sub2, -1);
  1639.                 sub1.removeAll();
  1640.             }
  1641.         }
  1642.  
  1643.         spComponent = null;
  1644.     }
  1645.  
  1646.     /**
  1647.      * Split a SplitterPanel into two panes.  This creates
  1648.      * two new SplitterPanels which are added to the original
  1649.      * SplitterPanel and are located inside according to the
  1650.      * split type.
  1651.      * @param splitType SPLIT_VER or SPLIT_HOR to request
  1652.      * vertical or horizontal splits
  1653.      * @return the first new SplitterPanel if successful
  1654.      * @see #SPLIT_VER
  1655.      * @see #SPLIT_HOR
  1656.      */
  1657.     public SplitterPanel split(int splitType)
  1658.     {
  1659.         return split(splitType, null, null);
  1660.     }
  1661.  
  1662.     /**
  1663.      * Split a SplitterPanel into two panes and add two
  1664.      * components.
  1665.      * @param splitType SPLIT_VER or SPLIT_HOR to request
  1666.      * vertical or horizontal splits
  1667.      * @param theComp1 the first component (left or top)
  1668.      * @param theComp2 the second component (left or top)
  1669.      * @return the first new SplitterPanel if successful
  1670.      * @see #SPLIT_VER
  1671.      * @see #SPLIT_HOR
  1672.      */
  1673.     public synchronized SplitterPanel split(int splitType, Component theComp1, Component theComp2)
  1674.     {
  1675.         if (isOuter)
  1676.             return(this.innerSP.split(splitType, theComp1, theComp2));
  1677.  
  1678.         if (this.splitType != SPLIT_NONE)
  1679.             return null;
  1680.  
  1681.         if ((splitType != SPLIT_VER) && (splitType != SPLIT_HOR))
  1682.             return null;
  1683.  
  1684.         sub1 = new SplitterPanel(false);
  1685.         if (sub1 == null)
  1686.             return null;
  1687.  
  1688.         sub2 = new SplitterPanel(false);
  1689.         if (sub2 == null)
  1690.         {
  1691.             super.remove(sub1);
  1692.             return null;
  1693.         }
  1694.  
  1695.         this.splitType = splitType;
  1696.  
  1697.         sub1.outerSP = this.outerSP;
  1698.         sub2.outerSP = this.outerSP;
  1699.  
  1700.         super.add(sub1, -1);
  1701.         super.add(sub2, -1);
  1702.  
  1703.         if (theComp1 != null)
  1704.             sub1.add(theComp1);
  1705.  
  1706.         if (theComp2 != null)
  1707.             sub2.add(theComp2);
  1708.  
  1709.         return sub1;
  1710.     }
  1711.  
  1712.     /**
  1713.      * Layout managers are not used with this panel. Overridden to be empty.
  1714.      */
  1715.     public void setLayout(LayoutManager mgr)
  1716.     {
  1717.     }
  1718.  
  1719.     private Frame findFrame()
  1720.     {
  1721.         Class theFrameClass;
  1722.         Container theContainer = this;
  1723.         Class theClass = this.getClass();
  1724.  
  1725.         try
  1726.         {
  1727.             theFrameClass =  Class.forName("java.awt.Frame"); //(new Frame()).getClass();
  1728.         }
  1729.         catch (ClassNotFoundException e)
  1730.         {
  1731.             return null;
  1732.         }
  1733.  
  1734.         while (theContainer != null)
  1735.         {
  1736.             theContainer = theContainer.getParent();
  1737.             theClass = theContainer.getClass();
  1738.             while ((theClass != theFrameClass) && (theClass != null))
  1739.             {
  1740.                 theClass = theClass.getSuperclass();
  1741.             }
  1742.             if (theClass == theFrameClass)
  1743.                 return (Frame)theContainer;
  1744.         }
  1745.  
  1746.         return null;
  1747.     }
  1748.  
  1749.     private void resetCursor()
  1750.     {
  1751.         Frame theFrame;
  1752.  
  1753.         if (outerSP.cursorChanged == false) return;
  1754.  
  1755.         theFrame = findFrame();
  1756.         if (theFrame == null)
  1757.             return;
  1758.  
  1759.         try
  1760.         {
  1761.             theFrame.setCursor(theFrame.DEFAULT_CURSOR);
  1762.             outerSP.cursorChanged = false;
  1763.             cursorCh = null;
  1764.         }
  1765.         catch(IllegalArgumentException e)
  1766.         {
  1767.             return;
  1768.         }
  1769.     }
  1770.  
  1771.     private int setCursor(int cursorID)
  1772.     {
  1773.         Frame theFrame;
  1774.  
  1775.         if (outerSP.cursorChanged)
  1776.             return cursorID;
  1777.         
  1778.         if (!isOuter)
  1779.             return outerSP.setCursor(cursorID);
  1780.  
  1781.         theFrame = findFrame();
  1782.         if (theFrame == null)
  1783.             return Integer.MIN_VALUE;
  1784.  
  1785.         try
  1786.         {
  1787.             theFrame.setCursor(cursorID);
  1788.             cursorChanged = true;
  1789.         }
  1790.         catch(IllegalArgumentException e)
  1791.         {
  1792.             return Integer.MIN_VALUE;
  1793.         }
  1794.  
  1795.         return cursorID;
  1796.     }
  1797.  
  1798.     private boolean inComponent(Component comp, int x, int y)
  1799.     {
  1800.         //Point compLoc = comp.location();
  1801.         Rectangle r = comp.bounds();
  1802.         r.grow(-iBdrSize-1, -iBdrSize-1);
  1803.         //return comp.inside(x - compLoc.x, y - compLoc.y);
  1804.         return ((x-r.x >= 0) && (x-r.x <= r.width) && (y-r.y >= 0) && (y-r.y <= r.height));
  1805.     }
  1806.  
  1807.     private boolean inGap(Event evt)
  1808.     {
  1809.         return inGap(evt.x, evt.y);
  1810.     }
  1811.  
  1812.     private boolean inGap(int evtX, int evtY)
  1813.     {
  1814.         if (inGap1(evtX, evtY))
  1815.             return true;
  1816.  
  1817.         if (isOuter)
  1818.         {
  1819.             return innerSP.inGap(evtX - innerSP.curLoc.x, evtY - innerSP.curLoc.y);
  1820.         }
  1821.         else if ((splitType == SPLIT_HOR) || (splitType == SPLIT_VER))
  1822.         {
  1823.             return (sub1.inGap(evtX - sub1.curLoc.x, evtY - sub1.curLoc.y)  ||
  1824.                     sub2.inGap(evtX - sub2.curLoc.x, evtY - sub2.curLoc.y));
  1825.         }
  1826.  
  1827.         return false;
  1828.     }
  1829.  
  1830.     private boolean inGap1(int evtX, int evtY)
  1831.     {
  1832.         if (!inside(evtX, evtY))
  1833.             return false;
  1834.  
  1835.         if (isOuter)
  1836.         {
  1837.             return false;
  1838.         }
  1839.         
  1840.         if (inOutBoarder(evtX, evtY)) {
  1841.             return false;    
  1842.         }
  1843.         else if ((splitType == SPLIT_HOR) || (splitType == SPLIT_VER))
  1844.         {
  1845.             if (inComponent(sub1, evtX, evtY) || (inComponent(sub2, evtX, evtY)))
  1846.             {
  1847.                 return false;
  1848.             }
  1849.             else
  1850.             {
  1851.                 if (inComponent(this, evtX, evtY)) cursorCh = this;
  1852.                 return true;
  1853.             }
  1854.         }
  1855.         else
  1856.         {
  1857.             return false;
  1858.         }
  1859.  
  1860.     }
  1861.     
  1862.     private boolean inOutBoarder(int evtX, int evtY) {
  1863.         Component sp = this;
  1864.         Rectangle r = sp.bounds();
  1865.         int x = r.x;
  1866.         int y = r.y;
  1867.         
  1868.         while(sp != outerSP) {
  1869.             sp = sp.getParent();
  1870.             r = sp.bounds();
  1871.             x += r.x;
  1872.             y += r.y;
  1873.         } 
  1874.         r.grow(-(outerSP.iBdrSize + outerSP.oBdrSize + outerSP.oGapWidth/2+4), -(outerSP.iBdrSize + outerSP.oBdrSize + outerSP.oGapHeight/2+4));
  1875.         r.move(r.x + outerSP.oGapWidth/2, r.y + outerSP.oGapHeight/2);
  1876.         return !r.inside(x + evtX, y + evtY);
  1877.     }
  1878.  
  1879.     /**
  1880.      * Override this method if you want a behavior when events
  1881.      * occur in the outer gap.  Be sure to call super.oGapThis
  1882.      * if you do override this method.  Note that it is recommended
  1883.      * that you place a SplitterPanel inside of a frame and set
  1884.      * outer border and gap sizes to zero if you want the end user
  1885.      * to be able to resize.
  1886.      * @param evt the event that occurred in the outer gap around
  1887.      * a SplitterPanel
  1888.      */
  1889.     public boolean oGapThis(Event evt)
  1890.     {
  1891.         if (!doMoveSplit && !inGap(evt))
  1892.             resetCursor();
  1893.  
  1894.         return true;
  1895.     }
  1896.  
  1897.     /**
  1898.      * The standard object string generator.
  1899.      * @return a meaningful string about this object
  1900.      */
  1901.     public String toString()
  1902.     {
  1903.         String typeString = "Bad Panel ";
  1904.         Container theParent;
  1905.         String theParentString;
  1906.  
  1907.         if (isOuter)
  1908.         {
  1909.             typeString = "Outer ";
  1910.         }
  1911.         else
  1912.         {
  1913.             if (splitType == SPLIT_NONE)
  1914.             {
  1915.                 typeString = "Unsplit ";
  1916.             }
  1917.             if (splitType == SPLIT_VER)
  1918.             {
  1919.                 typeString = "Vertically split ";
  1920.             }
  1921.             if (splitType == SPLIT_HOR)
  1922.             {
  1923.                 typeString = "Horizontally split ";
  1924.             }
  1925.         }
  1926.  
  1927.         theParent = getParent();
  1928.         if (theParent == null)
  1929.             theParentString = " with no parent (not added)";
  1930.  
  1931.         else
  1932.             theParentString = " with parent @" + theParent.hashCode();
  1933.  
  1934.         return typeString + super.toString() + ": @"  + hashCode() +  theParentString;
  1935.     }
  1936. }
  1937.