home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / main.bin / ScrollPane.java < prev    next >
Text File  |  1997-10-01  |  20KB  |  611 lines

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