home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / ScrollPane.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  18.7 KB  |  623 lines

  1. /*
  2.  * @(#)ScrollPane.java    1.54 98/03/18
  3.  *
  4.  * Copyright 1996, 1997 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package java.awt;
  15.  
  16. import java.awt.peer.ScrollPanePeer;
  17. import java.awt.event.*;
  18. import java.io.Serializable;
  19.  
  20.  
  21. /**
  22.  * A container class which implements automatic horizontal and/or
  23.  * vertical scrolling for a single child component.  The display
  24.  * policy for the scrollbars can be set to:
  25.  * <OL>
  26.  * <LI>as needed: scrollbars created and shown only when needed by scrollpane
  27.  * <LI>always: scrollbars created and always shown by the scrollpane
  28.  * <LI>never: scrollbars never created or shown by the scrollpane
  29.  * </OL>
  30.  * <P>
  31.  * The state of the horizontal and vertical scrollbars is represented
  32.  * by two objects (one for each dimension) which implement the
  33.  * Adjustable interface.  The API provides methods to access those
  34.  * objects such that the attributes on the Adjustable object (such as unitIncrement,
  35.  * value, etc.) can be manipulated.
  36.  * <P>
  37.  * Certain adjustable properties (minimum, maximum, blockIncrement,
  38.  * and visibleAmount) are set internally by the scrollpane in accordance
  39.  * with the geometry of the scrollpane and its child and these should
  40.  * not be set by programs using the scrollpane.
  41.  * <P>
  42.  * If the scrollbar display policy is defined as "never", then the
  43.  * scrollpane can still be programmatically scrolled using the 
  44.  * setScrollPosition() method and the scrollpane will move and clip
  45.  * the child's contents appropriately.  This policy is useful if the
  46.  * program needs to create and manage its own adjustable controls.
  47.  * <P>
  48.  * The placement of the scrollbars is controlled by platform-specific
  49.  * properties set by the user outside of the program.
  50.  * <P>
  51.  * The initial size of this container is set to 100x100, but can
  52.  * be reset using setSize(). 
  53.  * <P>
  54.  * Insets are used to define any space used by scrollbars and any
  55.  * borders created by the scroll pane. getInsets() can be used
  56.  * to get the current value for the insets.  If the value of 
  57.  * scrollbarsAlwaysVisible is false, then the value of the insets
  58.  * will change dynamically depending on whether the scrollbars are
  59.  * currently visible or not.    
  60.  *
  61.  * @version     1.54 03/18/98
  62.  * @author      Tom Ball
  63.  * @author      Amy Fowler
  64.  * @author      Tim Prinzing
  65.  */
  66. public class ScrollPane extends Container {
  67.  
  68.     
  69.     /**
  70.      * Initialize JNI field and method IDs
  71.      */
  72.     private static native void initIDs();
  73.  
  74.     static {
  75.         Toolkit.getDefaultToolkit();
  76.         initIDs();
  77.     }
  78.  
  79.     /**
  80.      * Specifies that horizontal/vertical scrollbar should be shown 
  81.      * only when the size of the child exceeds the size of the scrollpane
  82.      * in the horizontal/vertical dimension.
  83.      */
  84.     public static final int SCROLLBARS_AS_NEEDED = 0;
  85.  
  86.     /**
  87.      * Specifies that horizontal/vertical scrollbars should always be
  88.      * shown regardless of the respective sizes of the scrollpane and child.
  89.      */
  90.     public static final int SCROLLBARS_ALWAYS = 1;
  91.  
  92.     /**
  93.      * Specifies that horizontal/vertical scrollbars should never be shown
  94.      * regardless of the respective sizes of the scrollpane and child.
  95.      */
  96.     public static final int SCROLLBARS_NEVER = 2;
  97.  
  98.     private int scrollbarDisplayPolicy;
  99.     private ScrollPaneAdjustable vAdjustable;
  100.     private ScrollPaneAdjustable hAdjustable;
  101.  
  102.     private static final String base = "scrollpane";
  103.     private static int nameCounter = 0;
  104.  
  105.     /*
  106.      * JDK 1.1 serialVersionUID 
  107.      */
  108.      private static final long serialVersionUID = 7956609840827222915L;
  109.  
  110.     /**
  111.      * Create a new scrollpane container with a scrollbar display policy of
  112.      * "as needed".
  113.      */
  114.     public ScrollPane() {
  115.     this(SCROLLBARS_AS_NEEDED);
  116.     }
  117.  
  118.     /**
  119.      * Create a new scrollpane container.
  120.      * @param scrollbarDisplayPolicy policy for when scrollbars should be shown
  121.      */
  122.     public ScrollPane(int scrollbarDisplayPolicy) {
  123.         this.name = base + nameCounter++;
  124.     this.layoutMgr = null;
  125.     this.width = 100;
  126.     this.height = 100;
  127.     switch (scrollbarDisplayPolicy) {
  128.         case SCROLLBARS_NEVER:
  129.         case SCROLLBARS_AS_NEEDED:
  130.         case SCROLLBARS_ALWAYS:
  131.         this.scrollbarDisplayPolicy = scrollbarDisplayPolicy;
  132.         break;
  133.         default:
  134.         throw new IllegalArgumentException("illegal scrollbar display policy");
  135.     }
  136.  
  137.     vAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this), 
  138.                            Adjustable.VERTICAL);
  139.     hAdjustable = new ScrollPaneAdjustable(this, new PeerFixer(this), 
  140.                            Adjustable.HORIZONTAL);
  141.     }
  142.  
  143.     /** 
  144.      * Adds the specified component to this scroll pane container.
  145.      * If the scroll pane has an existing child component, that
  146.      * component is removed and the new one is added.  
  147.      * @param comp the component to be added 
  148.      * @param constraints  not applicable
  149.      * @param index position of child component (must be <= 0) 
  150.      */
  151.     protected final void addImpl(Component comp, Object constraints, int index) {
  152.         synchronized (Component.LOCK) {
  153.         if (getComponentCount() > 0) {
  154.         remove(0);
  155.         }
  156.         if (index > 0) {
  157.         throw new IllegalArgumentException("position greater than 0");
  158.         }
  159.         
  160.         super.addImpl(comp, constraints, index);
  161.     }
  162.     }
  163.  
  164.     /**
  165.      * Returns the display policy for the scrollbars.
  166.      * @return the display policy for the scrollbars
  167.      */
  168.     public int getScrollbarDisplayPolicy() {
  169.         return scrollbarDisplayPolicy;
  170.     }
  171.  
  172.     /**
  173.      * Returns the current size of the scroll pane's view port.
  174.      * @return the size of the view port in pixels
  175.      */
  176.     public Dimension getViewportSize() {
  177.     Insets i = getInsets();
  178.     return new Dimension(width - i.right - i.left,
  179.                  height - i.top - i.bottom);
  180.     }
  181.  
  182.     /**
  183.      * Returns the height that would be occupied by a horizontal
  184.      * scrollbar, which is independent of whether it is currently
  185.      * displayed by the scroll pane or not.
  186.      * @return the height of a horizontal scrollbar in pixels
  187.      */
  188.     public int getHScrollbarHeight() {
  189.     int h = 0;
  190.     if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
  191.         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  192.         if (peer != null) {
  193.         h = peer.getHScrollbarHeight();
  194.         }
  195.     }
  196.     return h;
  197.     }
  198.  
  199.     /**
  200.      * Returns the width that would be occupied by a vertical
  201.      * scrollbar, which is independent of whether it is currently
  202.      * displayed by the scroll pane or not.
  203.      * @return the width of a vertical scrollbar in pixels
  204.      */
  205.     public int getVScrollbarWidth() {
  206.     int w = 0;
  207.     if (scrollbarDisplayPolicy != SCROLLBARS_NEVER) {
  208.         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  209.         if (peer != null) {
  210.         w = peer.getVScrollbarWidth();
  211.         }
  212.     }
  213.     return w;
  214.     }
  215.  
  216.     /**
  217.      * Returns the Adjustable object which represents the state of
  218.      * the vertical scrollbar. If the scrollbar display policy is "never",
  219.      * this method returns null.
  220.      */
  221.     public Adjustable getVAdjustable() {
  222.         return vAdjustable;
  223.     }
  224.  
  225.     /**
  226.      * Returns the Adjustable object which represents the state of
  227.      * the horizontal scrollbar.  If the scrollbar display policy is "never",
  228.      * this method returns null.
  229.      */
  230.     public Adjustable getHAdjustable() {
  231.         return hAdjustable;
  232.     }
  233.  
  234.     /**
  235.      * Scrolls to the specified position within the child component.
  236.      * A call to this method is only valid if the scroll pane contains
  237.      * a child.  Specifying a position outside of the legal scrolling bounds
  238.      * of the child will scroll to the closest legal position.  
  239.      * Legal bounds are defined to be the rectangle: 
  240.      * x = 0, y = 0, width = (child width - view port width),
  241.      * height = (child height - view port height).
  242.      * This is a convenience method which interfaces with the Adjustable
  243.      * objects which represent the state of the scrollbars.
  244.      * @param x the x position to scroll to
  245.      * @param y the y position to scroll to
  246.      * @exception IllegalArgumentException if specified coordinates are
  247.      * not within the legal scrolling bounds of the child component.
  248.      */
  249.     public void setScrollPosition(int x, int y) {
  250.         synchronized (Component.LOCK) {
  251.         if (ncomponents <= 0) {
  252.         throw new NullPointerException("child is null");
  253.         }
  254.         hAdjustable.setValue(x);
  255.         vAdjustable.setValue(y);
  256.     }
  257.     }
  258.  
  259.    /**
  260.      * Scrolls to the specified position within the child component.
  261.      * A call to this method is only valid if the scroll pane contains
  262.      * a child and the specified position is within legal scrolling bounds
  263.      * of the child.  Legal bounds are defined to be the rectangle: 
  264.      * x = 0, y = 0, width = (child width - view port width),
  265.      * height = (child height - view port height).
  266.      * This is a convenience method which interfaces with the Adjustable
  267.      * objects which represent the state of the scrollbars.
  268.      * @param p the Point representing the position to scroll to
  269.      * @exception IllegalArgumentException if specified coordinates are
  270.      * not within the legal scrolling bounds of the child component.
  271.      */
  272.     public void setScrollPosition(Point p) {
  273.         setScrollPosition(p.x, p.y);
  274.     }
  275.  
  276.     /**
  277.      * Returns the current x,y position within the child which is displayed 
  278.      * at the 0,0 location of the scrolled panel's view port.
  279.      * This is a convenience method which interfaces with the adjustable
  280.      * objects which represent the state of the scrollbars.
  281.      * @return the coordinate position for the current scroll position
  282.      */
  283.     public Point getScrollPosition() {
  284.     if (ncomponents <= 0) {
  285.         throw new NullPointerException("child is null");
  286.     }
  287.     return new Point(hAdjustable.getValue(), vAdjustable.getValue()); 
  288.     }
  289.  
  290.     /** 
  291.      * Sets the layout manager for this container.  This method is
  292.      * overridden to prevent the layout mgr from being set.
  293.      * @param mgr the specified layout manager
  294.      */
  295.     public final void setLayout(LayoutManager mgr) {
  296.     throw new AWTError("ScrollPane controls layout");
  297.     }
  298.  
  299.     /**
  300.      * Lays out this container by resizing its child to its preferred size.
  301.      * If the new preferred size of the child causes the current scroll
  302.      * position to be invalid, the scroll position is set to the closest
  303.      * valid position.
  304.      *
  305.      * @see Component#validate
  306.      */
  307.     public void doLayout() {
  308.     layout();
  309.     }
  310.  
  311.     /**
  312.      * Determine the size to allocate the child component.
  313.      * If the viewport area is bigger than the childs 
  314.      * preferred size then the child is allocated enough
  315.      * to fill the viewport, otherwise the child is given
  316.      * it's preferred size.
  317.      */
  318.     Dimension calculateChildSize() {
  319.     Component c = getComponent(0);
  320.     Dimension cs = new Dimension(c.getPreferredSize());
  321.     Dimension size = getSize();
  322.     int vbarWidth = getVScrollbarWidth(); 
  323.     int hbarHeight = getHScrollbarHeight();
  324.     Insets i = getInsets();
  325.     boolean vbarOn = ((i.left + i.right) >= vbarWidth);
  326.     boolean hbarOn = ((i.top + i.bottom) >= hbarHeight);
  327.     int viewWidth = size.width - (i.left + i.right) - 
  328.         (vbarOn ? 0 : vbarWidth);
  329.     int viewHeight = size.height - (i.top + i.bottom) - 
  330.         (hbarOn ? 0 : hbarHeight);
  331.     boolean hbarNeeded = (cs.width > viewWidth);
  332.     boolean vbarNeeded = (cs.height > viewHeight);
  333.     
  334.     if (cs.width < viewWidth) {
  335.         cs.width = viewWidth + (vbarNeeded ? 0 : vbarWidth);
  336.     }
  337.     if (cs.height < viewHeight) {
  338.         cs.height = viewHeight + (hbarNeeded ? 0 : hbarHeight);
  339.     }
  340.  
  341.     return cs;
  342.     }
  343.  
  344.     /** 
  345.      * @deprecated As of JDK version 1.1,
  346.      * replaced by <code>doLayout()</code>.
  347.      */
  348.     public void layout() {
  349.     if (ncomponents > 0) {
  350.         Component c = getComponent(0);
  351.         Point p = c.getLocation();
  352.         Dimension cs = calculateChildSize();
  353.         Dimension vs = getViewportSize();    
  354.  
  355.         // update the child
  356.         int xPos = (cs.width > vs.width ?
  357.                Math.min(-p.x, cs.width - vs.width) :
  358.                -p.x);
  359.         int yPos = (cs.height > vs.height ?
  360.                Math.min(-p.y, cs.height - vs.height) :
  361.                -p.y);
  362.         c.reshape(-xPos, -yPos, cs.width, cs.height);
  363.         ScrollPanePeer peer = (ScrollPanePeer)this.peer;
  364.         if (peer != null) {
  365.             peer.childResized(cs.width, cs.height);
  366.         }
  367.  
  368.         // update adjustables... the viewport size may have changed
  369.         // with the scrollbars coming or going so the viewport size
  370.         // is updated before the adjustables.
  371.         vs = getViewportSize();
  372.         hAdjustable.setSpan(0, cs.width, vs.width);
  373.         vAdjustable.setSpan(0, cs.height, vs.height);
  374.     }
  375.     }
  376.  
  377.     /** 
  378.      * Prints the component in this scroll pane.
  379.      * @param g the specified Graphics window
  380.      * @see Component#print
  381.      * @see Component#printAll
  382.      */
  383.     public void printComponents(Graphics g) {
  384.     if (ncomponents > 0) {
  385.         Component c = component[0];
  386.         Point p = c.getLocation();
  387.         Dimension vs = getViewportSize();
  388.  
  389.         Graphics cg = g.create();
  390.         try {
  391.             cg.translate(p.x, p.y);
  392.         cg.clipRect(-(p.x), -(p.y), vs.width, vs.height);
  393.         c.printAll(cg);
  394.         } finally {
  395.         cg.dispose();
  396.         }
  397.     }
  398.     }
  399.  
  400.     /**
  401.      * Creates the scroll pane's peer. 
  402.      */
  403.     public void addNotify() {
  404.     peer = getToolkit().createScrollPane(this);
  405.     super.addNotify();
  406.     
  407.     if (getComponentCount() > 0) {
  408.         Component comp = getComponent(0);
  409.         if (comp.peer instanceof java.awt.peer.LightweightPeer) {
  410.         synchronized(Component.LOCK) {
  411.             // The scrollpane won't work with a windowless child... it assumes
  412.             // it is moving a child window around so the windowless child is
  413.             // wrapped with a window.
  414.             remove(0);
  415.             Panel child = new Panel();
  416.             child.setLayout(new BorderLayout());
  417.             child.add(comp);
  418.             add(child);
  419.         }
  420.         }
  421.     }
  422.     }
  423.  
  424.     public String paramString() {
  425.     String sdpStr;
  426.     switch (scrollbarDisplayPolicy) {
  427.         case SCROLLBARS_AS_NEEDED:
  428.         sdpStr = "as-needed";
  429.         break;
  430.         case SCROLLBARS_ALWAYS:
  431.         sdpStr = "always";
  432.         break;
  433.         case SCROLLBARS_NEVER:
  434.         sdpStr = "never";
  435.         break;
  436.         default:
  437.         sdpStr = "invalid display policy";
  438.     }
  439.     Point p = ncomponents > 0? getScrollPosition() : new Point(0,0);
  440.     Insets i = getInsets();        
  441.     return super.paramString()+",ScrollPosition=("+p.x+","+p.y+")"+
  442.         ",Insets=("+i.top+","+i.left+","+i.bottom+","+i.right+")"+
  443.         ",ScrollbarDisplayPolicy="+sdpStr;
  444.     }
  445.  
  446.     class PeerFixer implements AdjustmentListener, java.io.Serializable {
  447.  
  448.     PeerFixer(ScrollPane scroller) {
  449.         this.scroller = scroller;
  450.     }
  451.  
  452.     /**
  453.      * Invoked when the value of the adjustable has changed.
  454.      */   
  455.         public void adjustmentValueChanged(AdjustmentEvent e) {
  456.         Adjustable adj = e.getAdjustable();
  457.         int value = e.getValue();
  458.         ScrollPanePeer peer = (ScrollPanePeer) scroller.peer;
  459.         if (peer != null) {
  460.         peer.setValue(adj, value);
  461.         }
  462.         
  463.         Component c = scroller.getComponent(0);
  464.         switch(adj.getOrientation()) {
  465.         case Adjustable.VERTICAL:
  466.         c.move(c.getLocation().x, -(value));
  467.         break;
  468.         case Adjustable.HORIZONTAL:
  469.         c.move(-(value), c.getLocation().y);
  470.         break;
  471.         default:
  472.         throw new IllegalArgumentException("Illegal adjustable orientation");
  473.         }
  474.     }
  475.  
  476.         private ScrollPane scroller;
  477.     }
  478. }
  479.  
  480.  
  481. class ScrollPaneAdjustable implements Adjustable, java.io.Serializable {
  482.  
  483.     private ScrollPane sp;
  484.     private int orientation;
  485.     private int minimum;
  486.     private int maximum;
  487.     private int visibleAmount;
  488.     private int unitIncrement = 1;
  489.     private int blockIncrement = 1;
  490.     private int value;
  491.     private AdjustmentListener adjustmentListener;
  492.  
  493.     private static final String SCROLLPANE_ONLY = 
  494.         "Can be set by scrollpane only";
  495.  
  496.     /**
  497.      * Initialize JNI field and method ids
  498.      */
  499.     private static native void initIDs();
  500.  
  501.     static {
  502.         Toolkit.loadLibraries();
  503.         initIDs();
  504.     }        
  505.  
  506.     /*
  507.      * JDK 1.1 serialVersionUID 
  508.      */
  509.     private static final long serialVersionUID = -3359745691033257079L;
  510.  
  511.     public ScrollPaneAdjustable(ScrollPane sp, AdjustmentListener l, int orientation) {
  512.         this.sp = sp;
  513.         this.orientation = orientation;
  514.     addAdjustmentListener(l);
  515.     }
  516.  
  517.     /**
  518.      * This is called by the scrollpane itself to update the 
  519.      * min,max,visible values.  The scrollpane is the only one 
  520.      * that should be changing these since it is the source of
  521.      * these values.
  522.      */
  523.     void setSpan(int min, int max, int visible) {
  524.     // adjust the values to be reasonable
  525.     minimum = min;
  526.     maximum = Math.max(max, minimum + 1);
  527.     visibleAmount = Math.min(visible, maximum - minimum);
  528.     visibleAmount = Math.max(visibleAmount, 1);
  529.         blockIncrement = Math.max((int)(visible * .90), 1);
  530.     setValue(value);
  531.     }
  532.  
  533.     public int getOrientation() {
  534.         return orientation;
  535.     }
  536.  
  537.     public void setMinimum(int min) {
  538.     throw new AWTError(SCROLLPANE_ONLY);
  539.     }
  540.  
  541.     public int getMinimum() {
  542.         return 0;
  543.     }
  544.  
  545.     public void setMaximum(int max) {
  546.     throw new AWTError(SCROLLPANE_ONLY);
  547.     }   
  548.  
  549.     public int getMaximum() {
  550.         return maximum;
  551.     }
  552.  
  553.     public synchronized void setUnitIncrement(int u) {
  554.     if (u != unitIncrement) {
  555.         unitIncrement = u;
  556.         if (sp.peer != null) {
  557.         ScrollPanePeer peer = (ScrollPanePeer) sp.peer;
  558.         peer.setUnitIncrement(this, u);
  559.         }
  560.     }
  561.     } 
  562.   
  563.     public int getUnitIncrement() {
  564.         return unitIncrement;
  565.     }
  566.  
  567.     public synchronized void setBlockIncrement(int b) {
  568.         blockIncrement = b;
  569.     }    
  570.  
  571.     public int getBlockIncrement() {
  572.         return blockIncrement;
  573.     }
  574.  
  575.     public void setVisibleAmount(int v) {
  576.     throw new AWTError(SCROLLPANE_ONLY);
  577.     }
  578.  
  579.     public int getVisibleAmount() {
  580.         return visibleAmount;
  581.     }
  582.  
  583.     public void setValue(int v) {
  584.     // bounds check
  585.     v = Math.max(v, minimum);
  586.     v = Math.min(v, maximum - visibleAmount);
  587.  
  588.         if (v != value) {
  589.         value = v;
  590.         // Synchronously notify the listeners so that they are 
  591.         // guaranteed to be up-to-date with the Adjustable before
  592.         // it is mutated again.
  593.         AdjustmentEvent e = 
  594.         new AdjustmentEvent(this, AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED,
  595.                     AdjustmentEvent.TRACK, value);
  596.         adjustmentListener.adjustmentValueChanged(e);
  597.     }
  598.     }
  599.  
  600.     public int getValue() {
  601.         return value;
  602.     }
  603.  
  604.     public synchronized void addAdjustmentListener(AdjustmentListener l) {
  605.     adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l);
  606.     }
  607.  
  608.     public synchronized void removeAdjustmentListener(AdjustmentListener l){
  609.     adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l);
  610.     }
  611.  
  612.     public String toString() {
  613.     return getClass().getName() + "[" + paramString() + "]";
  614.     }
  615.  
  616.     public String paramString() {
  617.         return ((orientation==Adjustable.VERTICAL?"vertical,":"horizontal,")+
  618.           "[0.."+maximum+"],"+"val="+value+",vis="+visibleAmount+
  619.                 ",unit="+unitIncrement+",block="+blockIncrement);
  620.     }
  621. }
  622.  
  623.