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