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