001/* ScrollPaneLayout.java --
002   Copyright (C) 2002, 2004  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import java.awt.Component;
042import java.awt.Container;
043import java.awt.Dimension;
044import java.awt.Insets;
045import java.awt.LayoutManager;
046import java.awt.Rectangle;
047import java.io.Serializable;
048
049import javax.swing.border.Border;
050
051/**
052 * ScrollPaneLayout
053 * @author      Andrew Selkirk
054 * @version     1.0
055 */
056public 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}