1 /*
2  * Copyright (c) 2005, 2011, 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 package sun.swing;
26 
27 import java.awt.Container;
28 import java.awt.Insets;
29 import javax.swing.*;
30 import javax.swing.LayoutStyle.ComponentPlacement;
31 import javax.swing.border.Border;
32 import javax.swing.plaf.UIResource;
33 
34 /**
35  * An implementation of <code>LayoutStyle</code> that returns 6 for related
36  * components, otherwise 12.  This class also provides helper methods for
37  * subclasses.
38  *
39  */
40 public class DefaultLayoutStyle extends LayoutStyle {
41     private static final DefaultLayoutStyle INSTANCE =
42             new DefaultLayoutStyle();
43 
getInstance()44     public static LayoutStyle getInstance() {
45         return INSTANCE;
46     }
47 
48     @Override
getPreferredGap(JComponent component1, JComponent component2, ComponentPlacement type, int position, Container parent)49     public int getPreferredGap(JComponent component1, JComponent component2,
50             ComponentPlacement type, int position, Container parent) {
51         if (component1 == null || component2 == null || type == null) {
52             throw new NullPointerException();
53         }
54 
55         checkPosition(position);
56 
57         if (type == ComponentPlacement.INDENT &&
58                 (position == SwingConstants.EAST ||
59                  position == SwingConstants.WEST)) {
60             int indent = getIndent(component1, position);
61             if (indent > 0) {
62                 return indent;
63             }
64         }
65         return (type == ComponentPlacement.UNRELATED) ? 12 : 6;
66     }
67 
68     @Override
getContainerGap(JComponent component, int position, Container parent)69     public int getContainerGap(JComponent component, int position,
70                                Container parent) {
71         if (component == null) {
72             throw new NullPointerException();
73         }
74         checkPosition(position);
75         return 6;
76     }
77 
78     /**
79      * Returns true if the classes identify a JLabel and a non-JLabel
80      * along the horizontal axis.
81      */
isLabelAndNonlabel(JComponent c1, JComponent c2, int position)82     protected boolean isLabelAndNonlabel(JComponent c1, JComponent c2,
83                                          int position) {
84         if (position == SwingConstants.EAST ||
85                 position == SwingConstants.WEST) {
86             boolean c1Label = (c1 instanceof JLabel);
87             boolean c2Label = (c2 instanceof JLabel);
88             return ((c1Label || c2Label) && (c1Label != c2Label));
89         }
90         return false;
91     }
92 
93     /**
94      * For some look and feels check boxs and radio buttons typically
95      * don't paint the border, yet they have padding for a border.  Look
96      * and feel guidelines generally don't include this space.  Use
97      * this method to subtract this space from the specified
98      * components.
99      *
100      * @param source First component
101      * @param target Second component
102      * @param position Position doing layout along.
103      * @param offset Ideal offset, not including border/margin
104      * @return offset - border/margin around the component.
105      */
getButtonGap(JComponent source, JComponent target, int position, int offset)106     protected int getButtonGap(JComponent source, JComponent target,
107                                int position, int offset) {
108         offset -= getButtonGap(source, position);
109         if (offset > 0) {
110             offset -= getButtonGap(target, flipDirection(position));
111         }
112         if (offset < 0) {
113             return 0;
114         }
115         return offset;
116     }
117 
118     /**
119      * For some look and feels check boxs and radio buttons typically
120      * don't paint the border, yet they have padding for a border.  Look
121      * and feel guidelines generally don't include this space.  Use
122      * this method to subtract this space from the specified
123      * components.
124      *
125      * @param source Component
126      * @param position Position doing layout along.
127      * @param offset Ideal offset, not including border/margin
128      * @return offset - border/margin around the component.
129      */
getButtonGap(JComponent source, int position, int offset)130     protected int getButtonGap(JComponent source, int position, int offset) {
131         offset -= getButtonGap(source, position);
132         return Math.max(offset, 0);
133     }
134 
135     /**
136      * If <code>c</code> is a check box or radio button, and the border is
137      * not painted this returns the inset along the specified axis.
138      */
getButtonGap(JComponent c, int position)139     public int getButtonGap(JComponent c, int position) {
140         String classID = c.getUIClassID();
141         if ((classID == "CheckBoxUI" || classID == "RadioButtonUI") &&
142                 !((AbstractButton)c).isBorderPainted()) {
143             Border border = c.getBorder();
144             if (border instanceof UIResource) {
145                 return getInset(c, position);
146             }
147         }
148         return 0;
149     }
150 
checkPosition(int position)151     private void checkPosition(int position) {
152         if (position != SwingConstants.NORTH &&
153                 position != SwingConstants.SOUTH &&
154                 position != SwingConstants.WEST &&
155                 position != SwingConstants.EAST) {
156             throw new IllegalArgumentException();
157         }
158     }
159 
flipDirection(int position)160     protected int flipDirection(int position) {
161         switch(position) {
162         case SwingConstants.NORTH:
163             return SwingConstants.SOUTH;
164         case SwingConstants.SOUTH:
165             return SwingConstants.NORTH;
166         case SwingConstants.EAST:
167             return SwingConstants.WEST;
168         case SwingConstants.WEST:
169             return SwingConstants.EAST;
170         }
171         assert false;
172         return 0;
173     }
174 
175     /**
176      * Returns the amount to indent the specified component if it's
177      * a JCheckBox or JRadioButton.  If the component is not a JCheckBox or
178      * JRadioButton, 0 will be returned.
179      */
getIndent(JComponent c, int position)180     protected int getIndent(JComponent c, int position) {
181         String classID = c.getUIClassID();
182         if (classID == "CheckBoxUI" || classID == "RadioButtonUI") {
183             AbstractButton button = (AbstractButton)c;
184             Insets insets = c.getInsets();
185             Icon icon = getIcon(button);
186             int gap = button.getIconTextGap();
187             if (isLeftAligned(button, position)) {
188                 return insets.left + icon.getIconWidth() + gap;
189             } else if (isRightAligned(button, position)) {
190                 return insets.right + icon.getIconWidth() + gap;
191             }
192         }
193         return 0;
194     }
195 
getIcon(AbstractButton button)196     private Icon getIcon(AbstractButton button) {
197         Icon icon = button.getIcon();
198         if (icon != null) {
199             return icon;
200         }
201         String key = null;
202         if (button instanceof JCheckBox) {
203             key = "CheckBox.icon";
204         } else if (button instanceof JRadioButton) {
205             key = "RadioButton.icon";
206         }
207         if (key != null) {
208             Object oIcon = UIManager.get(key);
209             if (oIcon instanceof Icon) {
210                 return (Icon)oIcon;
211             }
212         }
213         return null;
214     }
215 
isLeftAligned(AbstractButton button, int position)216     private boolean isLeftAligned(AbstractButton button, int position) {
217         if (position == SwingConstants.WEST) {
218             boolean ltr = button.getComponentOrientation().isLeftToRight();
219             int hAlign = button.getHorizontalAlignment();
220             return ((ltr && (hAlign == SwingConstants.LEFT ||
221                              hAlign == SwingConstants.LEADING)) ||
222                     (!ltr && (hAlign == SwingConstants.TRAILING)));
223         }
224         return false;
225     }
226 
isRightAligned(AbstractButton button, int position)227     private boolean isRightAligned(AbstractButton button, int position) {
228         if (position == SwingConstants.EAST) {
229             boolean ltr = button.getComponentOrientation().isLeftToRight();
230             int hAlign = button.getHorizontalAlignment();
231             return ((ltr && (hAlign == SwingConstants.RIGHT ||
232                              hAlign == SwingConstants.TRAILING)) ||
233                     (!ltr && (hAlign == SwingConstants.LEADING)));
234         }
235         return false;
236     }
237 
getInset(JComponent c, int position)238     private int getInset(JComponent c, int position) {
239         return getInset(c.getInsets(), position);
240     }
241 
getInset(Insets insets, int position)242     private int getInset(Insets insets, int position) {
243         if (insets == null) {
244             return 0;
245         }
246         switch(position) {
247         case SwingConstants.NORTH:
248             return insets.top;
249         case SwingConstants.SOUTH:
250             return insets.bottom;
251         case SwingConstants.EAST:
252             return insets.right;
253         case SwingConstants.WEST:
254             return insets.left;
255         }
256         assert false;
257         return 0;
258     }
259 }
260