001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.jdesktop.layout;
043:
044: import java.awt.Component;
045: import java.awt.Container;
046: import java.awt.Insets;
047:
048: /**
049: * LayoutStyle is used to determine how much space to place between components
050: * during layout. LayoutStyle can be obtained for two components, or for
051: * a component relative to an edge of a parent container. The amount of
052: * space can vary depending upon whether or not the components are
053: * logically grouped together (<code>RELATED</code>).
054: * <p>
055: * This class is primarily useful for JREs prior to 1.6. In 1.6 API for this
056: * was added to Swing. When run on a JRE of 1.6 or greater this will call into
057: * the appropriate methods in Swing.
058: *
059: * @version $Revision$
060: */
061: public class LayoutStyle {
062: /**
063: * Possible argument to getPreferredGap. Used to indicate the two componets
064: * are grouped together.
065: */
066: public static final int RELATED = 0;
067: /**
068: * Possible argument to getPreferredGap. Used to indicate the two componets
069: * are not grouped together.
070: */
071: public static final int UNRELATED = 1;
072:
073: /**
074: * Possible argument to getPreferredGap. Used to indicate the distance
075: * to indent a component is being requested. To visually indicate
076: * a set of related components they will often times be horizontally
077: * indented, the <code>INDENT</code> constant for this.
078: * For example, to indent a check box relative to a label use this
079: * constant to <code>getPreferredGap</code>.
080: */
081: public static final int INDENT = 3;
082:
083: private static LayoutStyle layoutStyle;
084:
085: /**
086: * Sets the LayoutStyle instance to use for this look and feel.
087: * You generally don't need to invoke this, instead use the getter which
088: * will return the LayoutStyle appropriate for the current look and feel.
089: *
090: * @param layoutStyle the LayoutStyle to use; a value of null indicates
091: * the default should be used
092: */
093: public static void setSharedInstance(LayoutStyle layoutStyle) {
094: // UIManager.getLookAndFeelDefaults().put("LayoutStyle.instance",
095: // layoutStyle);
096: }
097:
098: /**
099: * Factory methods for obtaining the current <code>LayoutStyle</code>
100: * object appropriate for the current look and feel.
101: *
102: * @return the current LayoutStyle instance
103: */
104: public static LayoutStyle getSharedInstance() {
105: Object layoutImpl = null; //UIManager.get("LayoutStyle.instance");
106: if (layoutImpl != null && (layoutImpl instanceof LayoutStyle)) {
107: return (LayoutStyle) layoutImpl;
108: }
109: layoutStyle = new LayoutStyle();
110: return layoutStyle;
111: }
112:
113: /**
114: * Returns the amount of space to use between two components.
115: * The return value indicates the distance to place
116: * <code>component2</code> relative to <code>component1</code>.
117: * For example, the following returns the amount of space to place
118: * between <code>component2</code> and <code>component1</code>
119: * when <code>component2</code> is placed vertically above
120: * <code>component1</code>:
121: * <pre>
122: * int gap = getPreferredGap(component1, component2,
123: * LayoutStyle.RELATED,
124: * SwingConstants.NORTH, parent);
125: * </pre>
126: * The <code>type</code> parameter indicates the type
127: * of gap being requested. It can be one of the following values:
128: * <table>
129: * <tr><td><code>RELATED</code>
130: * <td>If the two components will be contained in
131: * the same parent and are showing similar logically related
132: * items, use <code>RELATED</code>.
133: * <tr><td><code>UNRELATED</code>
134: * <td>If the two components will be
135: * contained in the same parent but show logically unrelated items
136: * use <code>UNRELATED</code>.
137: * <tr><td><code>INDENT</code>
138: * <td>Used to obtain the preferred distance to indent a component
139: * relative to another. For example, if you want to horizontally
140: * indent a JCheckBox relative to a JLabel use <code>INDENT</code>.
141: * This is only useful for the horizontal axis.
142: * </table>
143: * <p>
144: * It's important to note that some look and feels may not distinguish
145: * between <code>RELATED</code> and <code>UNRELATED</code>.
146: * <p>
147: * The return value is not intended to take into account the
148: * current size and position of <code>component2</code> or
149: * <code>component1</code>. The return value may take into
150: * consideration various properties of the components. For
151: * example, the space may vary based on font size, or the preferred
152: * size of the component.
153: *
154: * @param component1 the <code>Component</code>
155: * <code>component2</code> is being placed relative to
156: * @param component2 the <code>Component</code> being placed
157: * @param type how the two components are being placed
158: * @param position the position <code>component2</code> is being placed
159: * relative to <code>component1</code>; one of
160: * <code>SwingConstants.NORTH</code>,
161: * <code>SwingConstants.SOUTH</code>,
162: * <code>SwingConstants.EAST</code> or
163: * <code>SwingConstants.WEST</code>
164: * @param parent the parent of <code>component2</code>; this may differ
165: * from the actual parent and may be null
166: * @return the amount of space to place between the two components
167: * @throws IllegalArgumentException if <code>position</code> is not
168: * one of <code>SwingConstants.NORTH</code>,
169: * <code>SwingConstants.SOUTH</code>,
170: * <code>SwingConstants.EAST</code> or
171: * <code>SwingConstants.WEST</code>; <code>type</code> not one
172: * of <code>INDENT</code>, <code>RELATED</code>
173: * or <code>UNRELATED</code>; or <code>component1</code> or
174: * <code>component2</code> is null
175: */
176: public int getPreferredGap(Component component1,
177: Component component2, int type, int position,
178: Container parent) {
179: if (position != 1 && //SwingConstants.NORTH &&
180: position != 5 && //SwingConstants.SOUTH &&
181: position != 7 && //SwingConstants.WEST &&
182: position != 3) { // SwingConstants.EAST) {
183: throw new IllegalArgumentException("Invalid position");
184: }
185: if (component1 == null || component2 == null) {
186: throw new IllegalArgumentException(
187: "Components must be non-null");
188: }
189: if (type != RELATED && type != UNRELATED && type != INDENT) {
190: throw new IllegalArgumentException("Invalid type");
191: }
192: return 4;
193: }
194:
195: /**
196: * Returns the amount of space to position a component inside its
197: * parent.
198: *
199: * @param component the <code>Component</code> being positioned
200: * @param position the position <code>component</code> is being placed
201: * relative to its parent; one of
202: * <code>SwingConstants.NORTH</code>,
203: * <code>SwingConstants.SOUTH</code>,
204: * <code>SwingConstants.EAST</code> or
205: * <code>SwingConstants.WEST</code>
206: * @param parent the parent of <code>component</code>; this may differ
207: * from the actual parent and may be null
208: * @return the amount of space to place between the component and specified
209: * edge
210: * @throws IllegalArgumentException if <code>position</code> is not
211: * one of <code>SwingConstants.NORTH</code>,
212: * <code>SwingConstants.SOUTH</code>,
213: * <code>SwingConstants.EAST</code> or
214: * <code>SwingConstants.WEST</code>;
215: * or <code>component</code> is null
216: */
217: public int getContainerGap(Component component, int position,
218: Container parent) {
219: if (position != 1 && //SwingConstants.NORTH &&
220: position != 5 && //SwingConstants.SOUTH &&
221: position != 7 && //SwingConstants.WEST &&
222: position != 3) { // SwingConstants.EAST) {
223: throw new IllegalArgumentException("Invalid position");
224: }
225: if (component == null) {
226: throw new IllegalArgumentException(
227: "Component must be non-null");
228: }
229: return 2;
230: }
231:
232: /**
233: * Returns true if <code>component</code> should be treated as a dialog.
234: */
235: boolean isDialog(Component component) {
236: // PENDING: tag the content pane to make this easier to check for
237: String name = component.getName();
238: return (name != null && name.endsWith(".contentPane"));
239: }
240:
241: /**
242: * For some look and feels check boxs and radio buttons have an empty
243: * border around them. Look and feel guidelines generally don't include
244: * this space. Use this method to subtract this space from the specified
245: * components.
246: *
247: * @param source First component
248: * @param target Second component
249: * @param position Position doing layout along.
250: * @param offset Ideal offset, not including border/margin
251: * @return offset - border/margin around the component.
252: */
253: int getCBRBPadding(Component source, Component target,
254: int position, int offset) {
255: offset -= getCBRBPadding(source, position);
256: if (offset > 0) {
257: offset -= getCBRBPadding(target, flipDirection(position));
258: }
259: if (offset < 0) {
260: return 0;
261: }
262: return offset;
263: }
264:
265: /**
266: * For some look and feels check boxs and radio buttons have an empty
267: * border around them. Look and feel guidelines generally don't include
268: * this space. Use this method to subtract this space from the specified
269: * components.
270: *
271: * @param source Component
272: * @param position Position doing layout along.
273: * @param offset Ideal offset, not including border/margin
274: * @return offset - border/margin around the component.
275: */
276: int getCBRBPadding(Component source, int position, int offset) {
277: offset -= getCBRBPadding(source, position);
278: return Math.max(offset, 0);
279: }
280:
281: int flipDirection(int position) {
282: switch (position) {
283: case 1:
284: return 5;
285: case 5:
286: return 1;
287: case 3:
288: return 7;
289: case 7:
290: return 3;
291: }
292: return 0;
293: }
294:
295: private int getCBRBPadding(Component c, int position) {
296: // if (c.getUIClassID() == "CheckBoxUI" ||
297: // c.getUIClassID() == "RadioButtonUI") {
298: // Border border = c.getBorder();
299: // if (border instanceof UIResource) {
300: // return getInset(c, position);
301: // }
302: // }
303: return 0;
304: }
305:
306: private int getInset(Component c, int position) {
307: return 5;
308: }
309:
310: // private boolean isLeftAligned(AbstractButton button, int position) {
311: // if (position == SwingConstants.WEST) {
312: // boolean ltr = button.getComponentOrientation().isLeftToRight();
313: // int hAlign = button.getHorizontalAlignment();
314: // return ((ltr && (hAlign == SwingConstants.LEFT ||
315: // hAlign == SwingConstants.LEADING)) ||
316: // (!ltr && (hAlign == SwingConstants.TRAILING)));
317: // }
318: // return false;
319: // }
320:
321: // private boolean isRightAligned(AbstractButton button, int position) {
322: // if (position == SwingConstants.EAST) {
323: // boolean ltr = button.getComponentOrientation().isLeftToRight();
324: // int hAlign = button.getHorizontalAlignment();
325: // return ((ltr && (hAlign == SwingConstants.RIGHT ||
326: // hAlign == SwingConstants.TRAILING)) ||
327: // (!ltr && (hAlign == SwingConstants.LEADING)));
328: // }
329: // return false;
330: // }
331:
332: /**
333: * Returns the amount to indent the specified component if it's
334: * a JCheckBox or JRadioButton. If the component is not a JCheckBox or
335: * JRadioButton, 0 will be returned.
336: */
337: int getButtonChildIndent(Component c, int position) {
338: return 0;
339: }
340: }
|