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.Container;
045: import javax.swing.ButtonModel;
046: import javax.swing.DefaultButtonModel;
047: import javax.swing.JComponent;
048: import javax.swing.JToggleButton;
049: import javax.swing.SwingConstants;
050: import javax.swing.plaf.metal.MetalLookAndFeel;
051: import javax.swing.plaf.metal.MetalTheme;
052: import java.lang.reflect.*;
053:
054: /**
055: * An implementation of <code>LayoutStyle</code> for the java look and feel.
056: * This information comes from the
057: * <a href="http://java.sun.com/products/jlf/ed2/book/HIG.Visual2.html">
058: * The Java Look and Feel Design Guidelines</a>.
059: *
060: * @version $Revision$
061: */
062: class MetalLayoutStyle extends LayoutStyle {
063: /**
064: * Whether or not we're using ocean, the default metal theme in 1.5.
065: */
066: private boolean isOcean;
067:
068: public MetalLayoutStyle() {
069: isOcean = false;
070: try {
071: Method method = MetalLookAndFeel.class.getMethod(
072: "getCurrentTheme", (Class[]) null);
073: isOcean = ((MetalTheme) method
074: .invoke(null, (Object[]) null)).getName() == "Ocean";
075: } catch (NoSuchMethodException nsme) {
076: } catch (IllegalAccessException iae) {
077: } catch (IllegalArgumentException iae2) {
078: } catch (InvocationTargetException ite) {
079: }
080: }
081:
082: // NOTE: The JLF makes reference to a number of guidelines in terms of
083: // 6 pixels - 1 pixel. The rationale is because steel buttons have
084: // a heavy border followed by a light border, and so that if you pad
085: // by 6 pixels it'll look like 7. Using 5 pixels than produces an effect
086: // of 6 pixels. With Ocean things are different, the only component
087: // that you want this behavior to happen with is checkboxs.
088:
089: public int getPreferredGap(JComponent source, JComponent target,
090: int type, int position, Container parent) {
091: // Invoke super to check arguments.
092: super .getPreferredGap(source, target, type, position, parent);
093:
094: if (type == INDENT) {
095: if (position == SwingConstants.EAST
096: || position == SwingConstants.WEST) {
097: int gap = getButtonChildIndent(source, position);
098: if (gap != 0) {
099: return gap;
100: }
101: return 12;
102: }
103: // Treat vertical INDENT as RELATED
104: type = RELATED;
105: }
106:
107: String sourceCID = source.getUIClassID();
108: String targetCID = target.getUIClassID();
109: int offset;
110:
111: if (type == RELATED) {
112: if (sourceCID == "ToggleButtonUI"
113: && targetCID == "ToggleButtonUI") {
114: ButtonModel sourceModel = ((JToggleButton) source)
115: .getModel();
116: ButtonModel targetModel = ((JToggleButton) target)
117: .getModel();
118: if ((sourceModel instanceof DefaultButtonModel)
119: && (targetModel instanceof DefaultButtonModel)
120: && (((DefaultButtonModel) sourceModel)
121: .getGroup() == ((DefaultButtonModel) targetModel)
122: .getGroup())
123: && ((DefaultButtonModel) sourceModel)
124: .getGroup() != null) {
125: // When toggle buttons are exclusive (that is, they form a
126: // radio button set), separate them with 2 pixels. This
127: // rule applies whether the toggle buttons appear in a
128: // toolbar or elsewhere in the interface.
129: // Note: this number does not appear to include any borders
130: // and so is not adjusted by the border of the toggle
131: // button
132: return 2;
133: }
134: // When toggle buttons are independent (like checkboxes)
135: // and used outside a toolbar, separate them with 5
136: // pixels.
137: if (isOcean) {
138: return 6;
139: }
140: return 5;
141: }
142: offset = 6;
143: } else {
144: offset = 12;
145: }
146: if ((position == SwingConstants.EAST || position == SwingConstants.WEST)
147: && ((sourceCID == "LabelUI" && targetCID != "LabelUI") || (sourceCID != "LabelUI" && targetCID == "LabelUI"))) {
148: // Insert 12 pixels between the trailing edge of a
149: // label and any associated components. Insert 12
150: // pixels between the trailing edge of a label and the
151: // component it describes when labels are
152: // right-aligned. When labels are left-aligned, insert
153: // 12 pixels between the trailing edge of the longest
154: // label and its associated component
155: return getCBRBPadding(source, target, position, offset + 6);
156: }
157: return getCBRBPadding(source, target, position, offset);
158: }
159:
160: int getCBRBPadding(JComponent source, JComponent target,
161: int position, int offset) {
162: offset = super .getCBRBPadding(source, target, position, offset);
163: if (offset > 0) {
164: int buttonAdjustment = getButtonAdjustment(source, position);
165: if (buttonAdjustment == 0) {
166: buttonAdjustment = getButtonAdjustment(target,
167: flipDirection(position));
168: }
169: offset -= buttonAdjustment;
170: }
171: if (offset < 0) {
172: return 0;
173: }
174: return offset;
175: }
176:
177: private int getButtonAdjustment(JComponent source, int edge) {
178: String uid = source.getUIClassID();
179: if (uid == "ButtonUI" || uid == "ToggleButtonUI") {
180: if (!isOcean
181: && (edge == SwingConstants.EAST || edge == SwingConstants.SOUTH)) {
182: return 1;
183: }
184: } else if (edge == SwingConstants.SOUTH) {
185: if (uid == "RadioButtonUI"
186: || (!isOcean && uid == "CheckBoxUI")) {
187: return 1;
188: }
189: }
190: return 0;
191: }
192:
193: public int getContainerGap(JComponent component, int position,
194: Container parent) {
195: super .getContainerGap(component, position, parent);
196: // Here's the rules we should be honoring:
197: //
198: // Include 11 pixels between the bottom and right
199: // borders of a dialog box and its command
200: // buttons. (To the eye, the 11-pixel spacing appears
201: // to be 12 pixels because the white borders on the
202: // lower and right edges of the button components are
203: // not visually significant.)
204: // NOTE: this last text was designed with Steel in mind, not Ocean.
205: //
206: // Insert 12 pixels between the edges of the panel and the
207: // titled border. Insert 11 pixels between the top of the
208: // title and the component above the titled border. Insert 12
209: // pixels between the bottom of the title and the top of the
210: // first label in the panel. Insert 11 pixels between
211: // component groups and between the bottom of the last
212: // component and the lower border.
213: return getCBRBPadding(component, position,
214: 12 - getButtonAdjustment(component, position));
215: }
216: }
|