1 /* 2 * Copyright (c) 2011, 2012, 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 */ 25 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.beans.*; 30 import java.lang.reflect.Method; 31 32 import javax.swing.*; 33 import javax.swing.border.Border; 34 import javax.swing.plaf.*; 35 36 import apple.laf.*; 37 import apple.laf.JRSUIConstants.*; 38 39 import com.apple.laf.AquaUtils.RecyclableSingleton; 40 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; 41 42 public class AquaUtilControlSize { 43 protected final static String CLIENT_PROPERTY_KEY = "JComponent.sizeVariant"; 44 protected final static String SYSTEM_PROPERTY_KEY = "swing.component.sizevariant"; 45 46 interface Sizeable { 47 void applySizeFor(final JComponent c, final Size size); 48 } 49 50 protected static final RecyclableSingleton<PropertySizeListener> sizeListener = new RecyclableSingletonFromDefaultConstructor<PropertySizeListener>(PropertySizeListener.class); 51 protected static PropertySizeListener getSizeListener() { 52 return sizeListener.get(); 53 } 54 55 protected static void addSizePropertyListener(final JComponent c) { 56 c.addPropertyChangeListener(CLIENT_PROPERTY_KEY, getSizeListener()); 57 PropertySizeListener.applyComponentSize(c, c.getClientProperty(CLIENT_PROPERTY_KEY)); 58 } 59 60 protected static void removeSizePropertyListener(final JComponent c) { 61 c.removePropertyChangeListener(CLIENT_PROPERTY_KEY, getSizeListener()); 62 } 63 64 private static JRSUIConstants.Size getSizeFromString(final String name) { 65 if ("regular".equalsIgnoreCase(name)) return Size.REGULAR; 66 if ("small".equalsIgnoreCase(name)) return Size.SMALL; 67 if ("mini".equalsIgnoreCase(name)) return Size.MINI; 68 if ("large".equalsIgnoreCase(name)) return Size.LARGE; 69 return null; 70 } 71 72 private static Size getDefaultSize() { 73 final String sizeProperty = java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction(SYSTEM_PROPERTY_KEY)); 74 final JRSUIConstants.Size size = getSizeFromString(sizeProperty); 75 if (size != null) return size; 76 return JRSUIConstants.Size.REGULAR; 77 } 78 79 protected final static JRSUIConstants.Size defaultSize = getDefaultSize(); 80 protected static JRSUIConstants.Size getUserSizeFrom(final JComponent c) { 81 final Object sizeProp = c.getClientProperty(CLIENT_PROPERTY_KEY); 82 if (sizeProp == null) return defaultSize; 83 final Size size = getSizeFromString(sizeProp.toString()); 84 if (size == null) return Size.REGULAR; 85 return size; 86 } 87 88 protected static JRSUIConstants.Size applySizeForControl(final JComponent c, final AquaPainter<? extends JRSUIState> painter) { 89 final JRSUIConstants.Size sizeFromUser = getUserSizeFrom(c); 90 final JRSUIConstants.Size size = sizeFromUser == null ? JRSUIConstants.Size.REGULAR : sizeFromUser; 91 painter.state.set(size); 92 return size; 93 } 94 95 protected static Font getFontForSize(final Component c, final JRSUIConstants.Size size) { 96 final Font initialFont = c.getFont(); 97 98 if (size == null || !(initialFont instanceof UIResource)) return initialFont; 99 100 if (size == JRSUIConstants.Size.MINI) return initialFont.deriveFont(AquaFonts.getMiniControlTextFont().getSize2D()); 101 if (size == JRSUIConstants.Size.SMALL) return initialFont.deriveFont(AquaFonts.getSmallControlTextFont().getSize2D()); 102 103 return initialFont.deriveFont(AquaFonts.getControlTextFont().getSize2D()); 104 } 105 106 private static void applyBorderForSize(final JComponent c, final Size size) { 107 final Border border = c.getBorder(); 108 if (!(border instanceof AquaBorder)) return; 109 final AquaBorder aquaBorder = (AquaBorder)border; 110 111 if (aquaBorder.sizeVariant.size == size) return; 112 final AquaBorder derivedBorder = aquaBorder.deriveBorderForSize(size); 113 if (derivedBorder == null) return; 114 115 c.setBorder(derivedBorder); 116 } 117 118 // call JComponent.getUI() if it exists, then call Sizeable.applySizeFor() if the UI is "Sizeable" 119 // next best thing to -respondsToSelector: :-P 120 private static void applyUISizing(final JComponent c, final Size size) { 121 try { 122 // see if this component has a "getUI" method 123 final Class<? extends JComponent> clazz = c.getClass(); 124 final Method getUIMethod = clazz.getMethod("getUI", new Class<?>[0]); 125 126 // see if that UI is one of ours that understands sizing 127 final Object ui = getUIMethod.invoke(c, new Object[0]); 128 if (!(ui instanceof Sizeable)) return; 129 130 // size it! 131 final Sizeable sizeable = (Sizeable)ui; 132 sizeable.applySizeFor(c, size); 133 } catch (final Throwable e) { return; } 134 } 135 136 protected static class PropertySizeListener implements PropertyChangeListener { 137 public void propertyChange(final PropertyChangeEvent evt) { 138 final String key = evt.getPropertyName(); 139 if (!CLIENT_PROPERTY_KEY.equalsIgnoreCase(key)) return; 140 141 final Object source = evt.getSource(); 142 if (!(source instanceof JComponent)) return; 143 144 final JComponent c = (JComponent)source; 145 applyComponentSize(c, evt.getNewValue()); 146 } 147 148 protected static void applyComponentSize(final JComponent c, final Object value) { 149 Size size = getSizeFromString(value == null ? null : value.toString()); 150 if (size == null) { 151 size = getUserSizeFrom(c); 152 if (size == Size.REGULAR) return; 153 } 154 155 applyBorderForSize(c, size); 156 157 applyUISizing(c, size); 158 159 final Font priorFont = c.getFont(); 160 if (!(priorFont instanceof FontUIResource)) return; 161 c.setFont(getFontForSize(c, size)); 162 } 163 } 164 165 public static class SizeDescriptor { 166 SizeVariant regular; 167 SizeVariant small; 168 SizeVariant mini; 169 170 public SizeDescriptor(final SizeVariant variant) { 171 regular = deriveRegular(variant); 172 small = deriveSmall(new SizeVariant(regular)); 173 mini = deriveMini(new SizeVariant(small)); 174 } 175 176 public SizeVariant deriveRegular(final SizeVariant v) { 177 v.size = Size.REGULAR; 178 return v; 179 } 180 181 public SizeVariant deriveSmall(final SizeVariant v) { 182 v.size = Size.SMALL; 183 return v; 184 } 185 186 public SizeVariant deriveMini(final SizeVariant v) { 187 v.size = Size.MINI; 188 return v; 189 } 190 191 public SizeVariant get(final JComponent c) { 192 if (c == null) return regular; 193 return get(getUserSizeFrom(c)); 194 } 195 196 public SizeVariant get(final Size size) { 197 if (size == Size.REGULAR) return regular; 198 if (size == Size.SMALL) return small; 199 if (size == Size.MINI) return mini; 200 return regular; 201 } 202 203 public String toString() { 204 return "regular[" + regular + "] small[" + small + "] mini[" + mini + "]"; 205 } 206 } 207 208 public static class SizeVariant { 209 Size size = Size.REGULAR; 210 Insets insets = new InsetsUIResource(0, 0, 0, 0); 211 Insets margins = new InsetsUIResource(0, 0, 0, 0); 212 Float fontSize; 213 int w = 0; 214 int h = 0; 215 // Integer textBaseline; 216 217 public SizeVariant() { } 218 219 public SizeVariant(final int minWidth, final int minHeight) { 220 this.w = minWidth; 221 this.h = minHeight; 222 } 223 224 public SizeVariant(final SizeVariant desc){ 225 this.size = desc.size; 226 this.insets = new InsetsUIResource(desc.insets.top, desc.insets.left, desc.insets.bottom, desc.insets.right); 227 this.margins = new InsetsUIResource(desc.margins.top, desc.margins.left, desc.margins.bottom, desc.margins.right); 228 this.fontSize = desc.fontSize; 229 this.w = desc.w; 230 this.h = desc.h; 231 // this.textBaseline = desc.textBaseline; 232 } 233 234 public SizeVariant replaceInsets(final String insetName) { 235 this.insets = UIManager.getInsets(insetName); 236 return this; 237 } 238 239 public SizeVariant replaceInsets(final Insets i) { 240 this.insets = new InsetsUIResource(i.top, i.left, i.bottom, i.right); 241 return this; 242 } 243 244 public SizeVariant alterInsets(final int top, final int left, final int bottom, final int right) { 245 insets = generateInsets(insets, top, left, bottom, right); 246 return this; 247 } 248 249 public SizeVariant replaceMargins(final String marginName) { 250 this.margins = UIManager.getInsets(marginName); 251 return this; 252 } 253 254 public SizeVariant alterMargins(final int top, final int left, final int bottom, final int right) { 255 margins = generateInsets(margins, top, left, bottom, right); 256 return this; 257 } 258 259 public SizeVariant alterFontSize(final float newSize) { 260 final float oldSize = fontSize == null ? 0.0f : fontSize.floatValue(); 261 fontSize = new Float(newSize + oldSize); 262 return this; 263 } 264 265 public SizeVariant alterMinSize(final int width, final int height) { 266 this.w += width; this.h += height; 267 return this; 268 } 269 270 // public SizeVariant alterTextBaseline(final int baseline) { 271 // final int oldSize = textBaseline == null ? 0 : textBaseline.intValue(); 272 // textBaseline = new Integer(baseline + oldSize); 273 // return this; 274 // } 275 276 static Insets generateInsets(final Insets i, final int top, final int left, final int bottom, final int right) { 277 if (i == null) return new InsetsUIResource(top, left, bottom, right); 278 i.top += top; 279 i.left += left; 280 i.bottom += bottom; 281 i.right += right; 282 return i; 283 } 284 285 public String toString() { 286 return "insets:" + insets + ", margins:" + margins + ", fontSize:" + fontSize;// + ", textBaseline:" + textBaseline; 287 } 288 } 289 }