1 /* 2 * Copyright (C) 2005-2006 Sun Microsystems, Inc. All rights reserved. Use is 3 * subject to license terms. 4 */ 5 6 package org.jdesktop.layout; 7 8 import java.awt.Container; 9 import javax.swing.ButtonModel; 10 import javax.swing.DefaultButtonModel; 11 import javax.swing.JComponent; 12 import javax.swing.JToggleButton; 13 import javax.swing.SwingConstants; 14 import javax.swing.plaf.metal.MetalLookAndFeel; 15 import javax.swing.plaf.metal.MetalTheme; 16 import java.lang.reflect.*; 17 18 /** 19 * An implementation of <code>LayoutStyle</code> for the java look and feel. 20 * This information comes from the 21 * <a href="http://java.sun.com/products/jlf/ed2/book/HIG.Visual2.html"> 22 * The Java Look and Feel Design Guidelines</a>. 23 * 24 * @version $Revision: 1.7 $ 25 */ 26 class MetalLayoutStyle extends LayoutStyle { 27 /** 28 * Whether or not we're using ocean, the default metal theme in 1.5. 29 */ 30 private boolean isOcean; 31 MetalLayoutStyle()32 public MetalLayoutStyle() { 33 isOcean = false; 34 try { 35 Method method = MetalLookAndFeel.class. 36 getMethod("getCurrentTheme", (Class[])null); 37 isOcean = ((MetalTheme)method.invoke(null, (Object[])null)). 38 getName() == "Ocean"; 39 } catch (NoSuchMethodException nsme) { 40 } catch (IllegalAccessException iae) { 41 } catch (IllegalArgumentException iae2) { 42 } catch (InvocationTargetException ite) { 43 } 44 } 45 46 // NOTE: The JLF makes reference to a number of guidelines in terms of 47 // 6 pixels - 1 pixel. The rationale is because steel buttons have 48 // a heavy border followed by a light border, and so that if you pad 49 // by 6 pixels it'll look like 7. Using 5 pixels than produces an effect 50 // of 6 pixels. With Ocean things are different, the only component 51 // that you want this behavior to happen with is checkboxs. 52 getPreferredGap(JComponent source, JComponent target, int type, int position, Container parent)53 public int getPreferredGap(JComponent source, JComponent target, 54 int type, int position, Container parent) { 55 // Invoke super to check arguments. 56 super.getPreferredGap(source, target, type, position, parent); 57 58 if (type == INDENT) { 59 if (position == SwingConstants.EAST || position == SwingConstants.WEST) { 60 int gap = getButtonChildIndent(source, position); 61 if (gap != 0) { 62 return gap; 63 } 64 return 12; 65 } 66 // Treat vertical INDENT as RELATED 67 type = RELATED; 68 } 69 70 String sourceCID = source.getUIClassID(); 71 String targetCID = target.getUIClassID(); 72 int offset; 73 74 if (type == RELATED) { 75 if (sourceCID == "ToggleButtonUI" && 76 targetCID == "ToggleButtonUI") { 77 ButtonModel sourceModel = ((JToggleButton)source).getModel(); 78 ButtonModel targetModel = ((JToggleButton)target).getModel(); 79 if ((sourceModel instanceof DefaultButtonModel) && 80 (targetModel instanceof DefaultButtonModel) && 81 (((DefaultButtonModel)sourceModel).getGroup() == 82 ((DefaultButtonModel)targetModel).getGroup()) && 83 ((DefaultButtonModel)sourceModel).getGroup() != null) { 84 // When toggle buttons are exclusive (that is, they form a 85 // radio button set), separate them with 2 pixels. This 86 // rule applies whether the toggle buttons appear in a 87 // toolbar or elsewhere in the interface. 88 // Note: this number does not appear to include any borders 89 // and so is not adjusted by the border of the toggle 90 // button 91 return 2; 92 } 93 // When toggle buttons are independent (like checkboxes) 94 // and used outside a toolbar, separate them with 5 95 // pixels. 96 if (isOcean) { 97 return 6; 98 } 99 return 5; 100 } 101 offset = 6; 102 } 103 else { 104 offset = 12; 105 } 106 if ((position == SwingConstants.EAST || 107 position == SwingConstants.WEST) && 108 ((sourceCID == "LabelUI" && targetCID != "LabelUI") || 109 (sourceCID != "LabelUI" && targetCID == "LabelUI"))) { 110 // Insert 12 pixels between the trailing edge of a 111 // label and any associated components. Insert 12 112 // pixels between the trailing edge of a label and the 113 // component it describes when labels are 114 // right-aligned. When labels are left-aligned, insert 115 // 12 pixels between the trailing edge of the longest 116 // label and its associated component 117 return getCBRBPadding(source, target, position, offset + 6); 118 } 119 return getCBRBPadding(source, target, position, offset); 120 } 121 getCBRBPadding(JComponent source, JComponent target, int position, int offset)122 int getCBRBPadding(JComponent source, JComponent target, int position, 123 int offset) { 124 offset = super.getCBRBPadding(source, target, position, offset); 125 if (offset > 0) { 126 int buttonAdjustment = getButtonAdjustment(source, position); 127 if (buttonAdjustment == 0) { 128 buttonAdjustment = getButtonAdjustment(target, 129 flipDirection(position)); 130 } 131 offset -= buttonAdjustment; 132 } 133 if (offset < 0) { 134 return 0; 135 } 136 return offset; 137 } 138 getButtonAdjustment(JComponent source, int edge)139 private int getButtonAdjustment(JComponent source, int edge) { 140 String uid = source.getUIClassID(); 141 if (uid == "ButtonUI" || uid == "ToggleButtonUI") { 142 if (!isOcean && (edge == SwingConstants.EAST || 143 edge == SwingConstants.SOUTH)) { 144 return 1; 145 } 146 } 147 else if (edge == SwingConstants.SOUTH) { 148 if (uid == "RadioButtonUI" || (!isOcean && uid == "CheckBoxUI")) { 149 return 1; 150 } 151 } 152 return 0; 153 } 154 getContainerGap(JComponent component, int position, Container parent)155 public int getContainerGap(JComponent component, int position, 156 Container parent) { 157 super.getContainerGap(component, position, parent); 158 // Here's the rules we should be honoring: 159 // 160 // Include 11 pixels between the bottom and right 161 // borders of a dialog box and its command 162 // buttons. (To the eye, the 11-pixel spacing appears 163 // to be 12 pixels because the white borders on the 164 // lower and right edges of the button components are 165 // not visually significant.) 166 // NOTE: this last text was designed with Steel in mind, not Ocean. 167 // 168 // Insert 12 pixels between the edges of the panel and the 169 // titled border. Insert 11 pixels between the top of the 170 // title and the component above the titled border. Insert 12 171 // pixels between the bottom of the title and the top of the 172 // first label in the panel. Insert 11 pixels between 173 // component groups and between the bottom of the last 174 // component and the lower border. 175 return getCBRBPadding(component, position, 12 - 176 getButtonAdjustment(component, position)); 177 } 178 } 179