1/*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.swing;
27
28import java.awt.AWTError;
29import java.awt.LayoutManager;
30import java.awt.Component;
31import java.awt.Container;
32import java.awt.Rectangle;
33import java.awt.Point;
34import java.awt.Dimension;
35import java.awt.Insets;
36import java.io.Serializable;
37
38/**
39 * The default layout manager for <code>JViewport</code>.
40 * <code>ViewportLayout</code> defines
41 * a policy for layout that should be useful for most applications.
42 * The viewport makes its view the same size as the viewport,
43 * however it will not make the view smaller than its minimum size.
44 * As the viewport grows the view is kept bottom justified until
45 * the entire view is visible, subsequently the view is kept top
46 * justified.
47 * <p>
48 * <strong>Warning:</strong>
49 * Serialized objects of this class will not be compatible with
50 * future Swing releases. The current serialization support is
51 * appropriate for short term storage or RMI between applications running
52 * the same version of Swing.  As of 1.4, support for long term storage
53 * of all JavaBeans&trade;
54 * has been added to the <code>java.beans</code> package.
55 * Please see {@link java.beans.XMLEncoder}.
56 *
57 * @author Hans Muller
58 * @since 1.2
59 */
60@SuppressWarnings("serial") // Same-version serialization only
61public class ViewportLayout implements LayoutManager, Serializable
62{
63    // Single instance used by JViewport.
64    static ViewportLayout SHARED_INSTANCE = new ViewportLayout();
65
66    /**
67     * Adds the specified component to the layout. Not used by this class.
68     * @param name the name of the component
69     * @param c the component to be added
70     */
71    public void addLayoutComponent(String name, Component c) { }
72
73    /**
74     * Removes the specified component from the layout. Not used by
75     * this class.
76     * @param c the component to remove
77     */
78    public void removeLayoutComponent(Component c) { }
79
80
81    /**
82     * Returns the preferred dimensions for this layout given the components
83     * in the specified target container.
84     * @param parent the component which needs to be laid out
85     * @return a <code>Dimension</code> object containing the
86     *          preferred dimensions
87     * @see #minimumLayoutSize
88     */
89    public Dimension preferredLayoutSize(Container parent) {
90        Component view = ((JViewport)parent).getView();
91        if (view == null) {
92            return new Dimension(0, 0);
93        }
94        else if (view instanceof Scrollable) {
95            return ((Scrollable)view).getPreferredScrollableViewportSize();
96        }
97        else {
98            return view.getPreferredSize();
99        }
100    }
101
102
103    /**
104     * Returns the minimum dimensions needed to layout the components
105     * contained in the specified target container.
106     *
107     * @param parent the component which needs to be laid out
108     * @return a <code>Dimension</code> object containing the minimum
109     *          dimensions
110     * @see #preferredLayoutSize
111     */
112    public Dimension minimumLayoutSize(Container parent) {
113        return new Dimension(4, 4);
114    }
115
116
117    /**
118     * Called by the AWT when the specified container needs to be laid out.
119     *
120     * @param parent  the container to lay out
121     *
122     * @throws AWTError if the target isn't the container specified to the
123     *                      <code>BoxLayout</code> constructor
124     */
125    public void layoutContainer(Container parent)
126    {
127        JViewport vp = (JViewport)parent;
128        Component view = vp.getView();
129        Scrollable scrollableView = null;
130
131        if (view == null) {
132            return;
133        }
134        else if (view instanceof Scrollable) {
135            scrollableView = (Scrollable) view;
136        }
137
138        /* All of the dimensions below are in view coordinates, except
139         * vpSize which we're converting.
140         */
141
142        Insets insets = vp.getInsets();
143        Dimension viewPrefSize = view.getPreferredSize();
144        Dimension vpSize = vp.getSize();
145        Dimension extentSize = vp.toViewCoordinates(vpSize);
146        Dimension viewSize = new Dimension(viewPrefSize);
147
148        if (scrollableView != null) {
149            if (scrollableView.getScrollableTracksViewportWidth()) {
150                viewSize.width = vpSize.width;
151            }
152            if (scrollableView.getScrollableTracksViewportHeight()) {
153                viewSize.height = vpSize.height;
154            }
155        }
156
157        Point viewPosition = vp.getViewPosition();
158
159        /* If the new viewport size would leave empty space to the
160         * right of the view, right justify the view or left justify
161         * the view when the width of the view is smaller than the
162         * container.
163         */
164        if (scrollableView == null ||
165            vp.getParent() == null ||
166            vp.getParent().getComponentOrientation().isLeftToRight()) {
167            if ((viewPosition.x + extentSize.width) > viewSize.width) {
168                viewPosition.x = Math.max(0, viewSize.width - extentSize.width);
169            }
170        } else {
171            if (extentSize.width > viewSize.width) {
172                viewPosition.x = viewSize.width - extentSize.width;
173            } else {
174                viewPosition.x = Math.max(0, Math.min(viewSize.width - extentSize.width, viewPosition.x));
175            }
176        }
177
178        /* If the new viewport size would leave empty space below the
179         * view, bottom justify the view or top justify the view when
180         * the height of the view is smaller than the container.
181         */
182        if ((viewPosition.y + extentSize.height) > viewSize.height) {
183            viewPosition.y = Math.max(0, viewSize.height - extentSize.height);
184        }
185
186        /* If we haven't been advised about how the viewports size
187         * should change wrt to the viewport, i.e. if the view isn't
188         * an instance of Scrollable, then adjust the views size as follows.
189         *
190         * If the origin of the view is showing and the viewport is
191         * bigger than the views preferred size, then make the view
192         * the same size as the viewport.
193         */
194        if (scrollableView == null) {
195            if ((viewPosition.x == 0) && (vpSize.width > viewPrefSize.width)) {
196                viewSize.width = vpSize.width;
197            }
198            if ((viewPosition.y == 0) && (vpSize.height > viewPrefSize.height)) {
199                viewSize.height = vpSize.height;
200            }
201        }
202        vp.setViewPosition(viewPosition);
203        vp.setViewSize(viewSize);
204    }
205}
206