001    /* ScrollPaneLayout.java --
002       Copyright (C) 2002, 2004  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import java.awt.Component;
042    import java.awt.Container;
043    import java.awt.Dimension;
044    import java.awt.Insets;
045    import java.awt.LayoutManager;
046    import java.awt.Rectangle;
047    import java.io.Serializable;
048    
049    import javax.swing.border.Border;
050    
051    /**
052     * ScrollPaneLayout
053     * @author      Andrew Selkirk
054     * @version     1.0
055     */
056    public class ScrollPaneLayout
057      implements LayoutManager, ScrollPaneConstants, Serializable
058    {
059      private static final long serialVersionUID = -4480022884523193743L;
060    
061      public static class UIResource extends ScrollPaneLayout
062        implements javax.swing.plaf.UIResource
063      {
064        public UIResource()
065        {
066          super();
067        }
068      }
069    
070      protected JViewport viewport;
071      protected JScrollBar vsb;
072      protected JScrollBar hsb;
073      protected JViewport rowHead;
074      protected JViewport colHead;
075      protected Component lowerLeft;
076      protected Component lowerRight;
077      protected Component upperLeft;
078      protected Component upperRight;
079      protected int vsbPolicy;
080      protected int hsbPolicy;
081    
082      public ScrollPaneLayout()
083      {
084            // Nothing to do here.
085      }
086    
087      public void syncWithScrollPane(JScrollPane scrollPane)
088      {
089        viewport = scrollPane.getViewport();
090        rowHead = scrollPane.getRowHeader();
091        colHead = scrollPane.getColumnHeader();
092        vsb = scrollPane.getVerticalScrollBar();
093        hsb = scrollPane.getHorizontalScrollBar();
094        vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
095        hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
096        lowerLeft = scrollPane.getCorner(LOWER_LEFT_CORNER);
097        lowerRight = scrollPane.getCorner(LOWER_RIGHT_CORNER);
098        upperLeft = scrollPane.getCorner(UPPER_LEFT_CORNER);
099        upperRight = scrollPane.getCorner(UPPER_RIGHT_CORNER);
100      }
101    
102      /**
103       * Removes an existing component.  If oldComponent is not null
104       * and is not equal to newComponent, oldComponent must be removed
105       * from its parent.
106       * @param oldComponent the old Component that may need to be removed.
107       * @param newComponent the Component to add.
108       * @return the newComponent
109       */
110      protected Component addSingletonComponent(Component oldComponent,
111                                                Component newComponent)
112      {
113        if (oldComponent != null && oldComponent != newComponent)
114          oldComponent.getParent().remove(oldComponent);
115        return newComponent;
116      }
117    
118      /**
119       * Add the specified component to the layout.
120       * @param key must be one of VIEWPORT, VERTICAL_SCROLLBAR,
121       * HORIZONTAL_SCROLLBAR, ROW_HEADER, COLUMN_HEADER,
122       * LOWER_RIGHT_CORNER, LOWER_LEFT_CORNER, UPPER_RIGHT_CORNER,
123       * UPPER_LEFT_CORNER.
124       * @param component the Component to add
125       * @throws IllegalArgumentException if key is not as above
126       */
127      public void addLayoutComponent(String key, Component component)
128      {
129        if (key == VIEWPORT)
130          viewport = (JViewport) component;
131        else if (key == VERTICAL_SCROLLBAR)
132          vsb = (JScrollBar) component;
133        else if (key == HORIZONTAL_SCROLLBAR)
134          hsb = (JScrollBar) component;
135        else if (key == ROW_HEADER)
136          rowHead = (JViewport) component;
137        else if (key == COLUMN_HEADER)
138          colHead = (JViewport) component;
139        else if (key == LOWER_RIGHT_CORNER)
140          lowerRight = component;
141        else if (key == UPPER_RIGHT_CORNER)
142          upperRight = component;
143        else if (key == LOWER_LEFT_CORNER)
144          lowerLeft = component;
145        else if (key == UPPER_LEFT_CORNER)
146          upperLeft = component;
147        else
148          throw new IllegalArgumentException();
149      }
150    
151      public void removeLayoutComponent(Component component)
152      {
153        if (component == viewport)
154          viewport = null;
155        else if (component == vsb)
156          vsb = null;
157        else if (component == hsb)
158          hsb = null;
159        else if (component == rowHead)
160          rowHead = null;
161        else if (component == colHead)
162          colHead = null;
163        else if (component == lowerRight)
164          lowerRight = null;
165        else if (component == upperRight)
166          upperRight = null;
167        else if (component == lowerLeft)
168          lowerLeft = null;
169        else if (component == upperLeft)
170          upperLeft = null;
171      }
172    
173      public int getVerticalScrollBarPolicy()
174      {
175        return vsbPolicy;
176      }
177    
178      /**
179       * Sets the vertical scrollbar policy.
180       * @param policy must be one of VERTICAL_SCROLLBAR_AS_NEEDED,
181       * VERTICAL_SCROLLBAR_NEVER, VERTICAL_SCROLLBAR_ALWAYS.
182       * @throws IllegalArgumentException if policy is not one of the valid
183       * JScrollBar policies.
184       */
185      public void setVerticalScrollBarPolicy(int policy)
186      {
187        if (policy != VERTICAL_SCROLLBAR_AS_NEEDED &&
188            policy != VERTICAL_SCROLLBAR_NEVER &&
189            policy != VERTICAL_SCROLLBAR_ALWAYS)
190          throw new IllegalArgumentException("Illegal Scrollbar Policy");
191        vsbPolicy = policy;
192      }
193    
194      public int getHorizontalScrollBarPolicy()
195      {
196        return hsbPolicy;
197      }
198    
199      /**
200       * Sets the horizontal scrollbar policy.
201       * @param policy must be one of HORIZONTAL_SCROLLBAR_AS_NEEDED,
202       * HORIZONTAL_SCROLLBAR_NEVER, HORIZONTAL_SCROLLBAR_ALWAYS.
203       * @throws IllegalArgumentException if policy is not one of the valid
204       * JScrollbar policies.
205       */
206      public void setHorizontalScrollBarPolicy(int policy)
207      {
208        if (policy != HORIZONTAL_SCROLLBAR_AS_NEEDED &&
209            policy != HORIZONTAL_SCROLLBAR_NEVER &&
210            policy != HORIZONTAL_SCROLLBAR_ALWAYS)
211          throw new IllegalArgumentException("Illegal Scrollbar Policy");
212        hsbPolicy = policy;
213      }
214    
215      public JViewport getViewport()
216      {
217        return viewport;
218      }
219    
220      public JScrollBar getHorizontalScrollBar()
221      {
222        return hsb;
223      }
224    
225      public JScrollBar getVerticalScrollBar()
226      {
227        return vsb;
228      }
229    
230      public JViewport getRowHeader()
231      {
232        return rowHead;
233      }
234    
235      public JViewport getColumnHeader()
236      {
237        return colHead;
238      }
239    
240      /**
241       * Returns the Component at the specified corner.
242       * @param key the corner.
243       * @return the Component at the specified corner, or null if
244       * key is not one of the four valid corners.
245       */
246      public Component getCorner(String key)
247      {
248        if (key == LOWER_RIGHT_CORNER)
249          return lowerRight;
250        else if (key == UPPER_RIGHT_CORNER)
251          return upperRight;
252        else if (key == LOWER_LEFT_CORNER)
253          return lowerLeft;
254        else if (key == UPPER_LEFT_CORNER)
255          return upperLeft;
256        return null;
257      }
258    
259      public Dimension preferredLayoutSize(Container parent)
260      {
261        // Sun's implementation simply throws a ClassCastException if
262        // parent is no JScrollPane, so do we.
263        JScrollPane sc = (JScrollPane) parent;
264        Dimension viewportSize = viewport.getPreferredSize();
265        Dimension viewSize = viewport.getViewSize();
266        int width = viewportSize.width;
267        int height = viewportSize.height;
268    
269        // horizontal scrollbar needed if the view's preferred width
270        // is larger than the viewport's preferred width
271        if (hsb != null && viewSize.width > viewportSize.width)
272          height += hsb.getPreferredSize().height;
273    
274        // vertical scrollbar needed if the view's preferred height
275        // is larger than the viewport's preferred height
276        if (vsb != null && viewSize.height > viewportSize.height)
277          width += vsb.getPreferredSize().width;
278        if (rowHead != null && rowHead.isVisible())
279          width += rowHead.getPreferredSize().width;
280        if (colHead != null && colHead.isVisible())
281          height += colHead.getPreferredSize().height;
282    
283        // Add insets of viewportBorder if present.
284        Border vpBorder = sc.getViewportBorder();
285        if (vpBorder != null)
286          {
287            Insets i = vpBorder.getBorderInsets(sc);
288            width += i.left + i.right;
289            height += i.top + i.bottom;
290          }
291    
292        Insets i = sc.getInsets();
293        return new Dimension(width + i.left + i.right,
294                             height + i.left + i.right);
295      }
296    
297      public Dimension minimumLayoutSize(Container parent)
298      {
299        // Sun's implementation simply throws a ClassCastException if
300        // parent is no JScrollPane, so do we.
301        JScrollPane sc = (JScrollPane) parent;
302        Insets i = sc.getInsets();
303        Dimension viewportMinSize = sc.getViewport().getMinimumSize();
304    
305        int width = i.left + i.right + viewportMinSize.width;
306        if (sc.getVerticalScrollBarPolicy()
307            != JScrollPane.VERTICAL_SCROLLBAR_NEVER)
308          width += sc.getVerticalScrollBar().getMinimumSize().width;
309    
310        int height = i.top + i.bottom + viewportMinSize.height;
311        if (sc.getHorizontalScrollBarPolicy()
312            != JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
313          height += sc.getHorizontalScrollBar().getMinimumSize().height;
314    
315        // Add insets of viewportBorder if present.
316        Border vpBorder = sc.getViewportBorder();
317        if (vpBorder != null)
318          {
319            i = vpBorder.getBorderInsets(sc);
320            width += i.left + i.right;
321            height += i.top + i.bottom;
322          }
323    
324        return new Dimension(width, height);
325      }
326    
327      /**
328       *
329       *     +----+--------------------+----+ y1
330       *     | c1 |   column header    | c2 |
331       *     +----+--------------------+----+ y2
332       *     | r  |                    | v  |
333       *     | o  |                    |    |
334       *     | w  |                    | s  |
335       *     |    |                    | r  |
336       *     | h  |                    | o  |
337       *     | e  |      viewport      | l  |
338       *     | a  |                    | l  |
339       *     | d  |                    | b  |
340       *     | e  |                    | a  |
341       *     | r  |                    | r  |
342       *     +----+--------------------+----+ y3
343       *     | c3 |    h scrollbar     | c4 |
344       *     +----+--------------------+----+ y4
345       *    x1   x2                   x3   x4
346       *
347       */
348      public void layoutContainer(Container parent)
349      {
350        // Sun's implementation simply throws a ClassCastException if
351        // parent is no JScrollPane, so do we.
352        JScrollPane sc = (JScrollPane) parent;
353        JViewport viewport = sc.getViewport();
354        Component view = viewport.getView();
355    
356        // If there is no view in the viewport, there is no work to be done.
357        if (view == null)
358          return;
359    
360        Dimension viewSize = viewport.getView().getPreferredSize();
361    
362        int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
363        int y1 = 0, y2 = 0, y3 = 0, y4 = 0;
364        Rectangle scrollPaneBounds = SwingUtilities.calculateInnerArea(sc, null);
365    
366        // If there is a viewportBorder, remove its insets from the available
367        // space.
368        Border vpBorder = sc.getViewportBorder();
369        Insets vpi;
370        if (vpBorder != null)
371          vpi = vpBorder.getBorderInsets(sc);
372        else
373          vpi = new Insets(0, 0, 0, 0);
374    
375        x1 = scrollPaneBounds.x;
376        y1 = scrollPaneBounds.y;
377        x4 = scrollPaneBounds.x + scrollPaneBounds.width;
378        y4 = scrollPaneBounds.y + scrollPaneBounds.height;
379        if (colHead != null)
380          y2 = y1 + colHead.getPreferredSize().height;
381        else
382          y2 = y1;
383    
384        if (rowHead != null)
385          x2 = x1 + rowHead.getPreferredSize().width;
386        else
387          x2 = x1;
388    
389        int vsbPolicy = sc.getVerticalScrollBarPolicy();
390        int hsbPolicy = sc.getHorizontalScrollBarPolicy();
391    
392        int vsWidth = 0;
393        int hsHeight = 0;
394    
395        boolean showVsb =
396          (vsb != null)
397          && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS)
398              || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
399                  && viewSize.height > (y4 - y2)));
400    
401        if (showVsb)
402          vsWidth = vsb.getPreferredSize().width;
403    
404        // The horizontal scroll bar may become necessary if the vertical scroll
405        // bar appears, reducing the space, left for the component.
406    
407        boolean showHsb =
408          (hsb != null)
409          && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS)
410              || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED
411                  && viewSize.width > (x4 - x2 - vsWidth)));
412    
413        if (showHsb)
414          hsHeight = hsb.getPreferredSize().height;
415    
416        // If the horizontal scroll bar appears, and the vertical scroll bar
417        // was not necessary assuming that there is no horizontal scroll bar,
418        // the vertical scroll bar may become necessary because the horizontal
419        // scroll bar reduces the vertical space for the component.
420        if (!showVsb)
421          {
422            showVsb =
423              (vsb != null)
424              && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS)
425                  || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED
426                      && viewSize.height > (y4 - y2)));
427    
428            if (showVsb)
429              vsWidth = vsb.getPreferredSize().width;
430          }
431    
432        x3 = x4 - vsWidth;
433        y3 = y4 - hsHeight;
434    
435        // now set the layout
436        if (viewport != null)
437          viewport.setBounds(new Rectangle(x2 + vpi.left, y2 + vpi.top,
438                                           x3 - x2 - vpi.left - vpi.right,
439                                           y3 - y2 - vpi.top - vpi.bottom));
440    
441        if (colHead != null)
442          colHead.setBounds(new Rectangle(x2, y1, x3 - x2, y2 - y1));
443    
444        if (rowHead != null)
445          rowHead.setBounds(new Rectangle(x1, y2, x2 - x1, y3 - y2));
446    
447        if (showVsb)
448          {
449            vsb.setVisible(true);
450            vsb.setBounds(new Rectangle(x3, y2, x4 - x3, y3 - y2 ));
451          }
452        else if (vsb != null)
453          vsb.setVisible(false);
454    
455        if (showHsb)
456          {
457            hsb.setVisible(true);
458            hsb.setBounds(new Rectangle(x2 , y3, x3 - x2, y4 - y3));
459          }
460        else if (hsb != null)
461          hsb.setVisible(false);
462    
463        if (upperLeft != null)
464          upperLeft.setBounds(new Rectangle(x1, y1, x2 - x1, y2 - y1));
465    
466        if (upperRight != null)
467          upperRight.setBounds(new Rectangle(x3, y1, x4 - x3, y2 - y1));
468    
469        if (lowerLeft != null)
470          lowerLeft.setBounds(new Rectangle(x1, y3, x2 - x1, y4 - y3));
471    
472        if (lowerRight != null)
473          lowerRight.setBounds(new Rectangle(x3, y3, x4 - x3, y4 - y3));
474      }
475    
476      /**
477       * Returns the bounds of the border around a ScrollPane's viewport.
478       *
479       * @param scrollPane the ScrollPane for which's viewport the border
480       *     is requested
481       *
482       * @deprecated As of Swing 1.1 replaced by
483       *     {@link javax.swing.JScrollPane#getViewportBorderBounds}.
484       */
485      public Rectangle getViewportBorderBounds(JScrollPane scrollPane)
486      {
487        return null;
488      }
489    
490    
491    }