View Javadoc
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 }