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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 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 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 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 238 private int getInset(JComponent c, int position) { 239 return getInset(c.getInsets(), position); 240 } 241 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