1 /*
2  * Copyright (c) 2002, 2014, 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 javax.swing.plaf.synth;
27 
28 import javax.swing.*;
29 import javax.swing.text.*;
30 import javax.swing.plaf.*;
31 import javax.swing.plaf.basic.BasicTextFieldUI;
32 import java.awt.*;
33 import java.awt.event.FocusEvent;
34 import java.awt.event.FocusListener;
35 import java.beans.PropertyChangeEvent;
36 
37 
38 /**
39  * Provides the Synth L&F UI delegate for {@link javax.swing.JTextField}.
40  * <p>
41  * <strong>Warning:</strong>
42  * Serialized objects of this class will not be compatible with
43  * future Swing releases. The current serialization support is
44  * appropriate for short term storage or RMI between applications running
45  * the same version of Swing.  As of 1.4, support for long term storage
46  * of all JavaBeans
47  * has been added to the <code>java.beans</code> package.
48  * Please see {@link java.beans.XMLEncoder}.
49  *
50  * @author  Shannon Hickey
51  * @since 1.7
52  */
53 @SuppressWarnings("serial") // Same-version serialization only
54 public class SynthTextFieldUI extends BasicTextFieldUI implements SynthUI {
55     private Handler handler = new Handler();
56     private SynthStyle style;
57     private boolean updateKBAction = true;
58 
59     /**
60      * Creates a UI for a JTextField.
61      *
62      * @param c the text field
63      * @return the UI object
64      */
createUI(JComponent c)65     public static ComponentUI createUI(JComponent c) {
66         return new SynthTextFieldUI();
67     }
68 
updateStyle(JTextComponent comp, boolean updateKBAction)69     private void updateStyle(JTextComponent comp, boolean updateKBAction) {
70         SynthContext context = getContext(comp, ENABLED);
71         SynthStyle oldStyle = style;
72 
73         style = SynthLookAndFeel.updateStyle(context, this);
74 
75         if (style != oldStyle) {
76             SynthTextFieldUI.updateStyle(comp, context, getPropertyPrefix());
77 
78             if (oldStyle != null && updateKBAction) {
79                 uninstallKeyboardActions();
80                 installKeyboardActions();
81             }
82         }
83     }
84 
updateStyle(JTextComponent comp, SynthContext context, String prefix)85     static void updateStyle(JTextComponent comp, SynthContext context,
86             String prefix) {
87         SynthStyle style = context.getStyle();
88 
89         Color color = comp.getCaretColor();
90         if (color == null || color instanceof UIResource) {
91             comp.setCaretColor(
92                 (Color)style.get(context, prefix + ".caretForeground"));
93         }
94 
95         Color fg = comp.getForeground();
96         if (fg == null || fg instanceof UIResource) {
97             fg = style.getColorForState(context, ColorType.TEXT_FOREGROUND);
98             if (fg != null) {
99                 comp.setForeground(fg);
100             }
101         }
102 
103         Object ar = style.get(context, prefix + ".caretAspectRatio");
104         if (ar instanceof Number) {
105             comp.putClientProperty("caretAspectRatio", ar);
106         }
107 
108         context.setComponentState(SELECTED | FOCUSED);
109 
110         Color s = comp.getSelectionColor();
111         if (s == null || s instanceof UIResource) {
112             comp.setSelectionColor(
113                 style.getColor(context, ColorType.TEXT_BACKGROUND));
114         }
115 
116         Color sfg = comp.getSelectedTextColor();
117         if (sfg == null || sfg instanceof UIResource) {
118             comp.setSelectedTextColor(
119                 style.getColor(context, ColorType.TEXT_FOREGROUND));
120         }
121 
122         context.setComponentState(DISABLED);
123 
124         Color dfg = comp.getDisabledTextColor();
125         if (dfg == null || dfg instanceof UIResource) {
126             comp.setDisabledTextColor(
127                 style.getColor(context, ColorType.TEXT_FOREGROUND));
128         }
129 
130         Insets margin = comp.getMargin();
131         if (margin == null || margin instanceof UIResource) {
132             margin = (Insets)style.get(context, prefix + ".margin");
133 
134             if (margin == null) {
135                 // Some places assume margins are non-null.
136                 margin = SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS;
137             }
138             comp.setMargin(margin);
139         }
140 
141         Caret caret = comp.getCaret();
142         if (caret instanceof UIResource) {
143             Object o = style.get(context, prefix + ".caretBlinkRate");
144             if (o != null && o instanceof Integer) {
145                 Integer rate = (Integer)o;
146                 caret.setBlinkRate(rate.intValue());
147             }
148         }
149     }
150 
151     /**
152      * {@inheritDoc}
153      */
154     @Override
getContext(JComponent c)155     public SynthContext getContext(JComponent c) {
156         return getContext(c, SynthLookAndFeel.getComponentState(c));
157     }
158 
getContext(JComponent c, int state)159     private SynthContext getContext(JComponent c, int state) {
160         return SynthContext.getContext(c, style, state);
161     }
162 
163     /**
164      * Notifies this UI delegate to repaint the specified component.
165      * This method paints the component background, then calls
166      * the {@link #paint(SynthContext,Graphics)} method.
167      *
168      * <p>In general, this method does not need to be overridden by subclasses.
169      * All Look and Feel rendering code should reside in the {@code paint} method.
170      *
171      * @param g the {@code Graphics} object used for painting
172      * @param c the component being painted
173      * @see #paint(SynthContext,Graphics)
174      */
175     @Override
update(Graphics g, JComponent c)176     public void update(Graphics g, JComponent c) {
177         SynthContext context = getContext(c);
178 
179         SynthLookAndFeel.update(context, g);
180         paintBackground(context, g, c);
181         paint(context, g);
182     }
183 
184     /**
185      * Paints the specified component.
186      * <p>This is routed to the {@link #paintSafely} method under
187      * the guarantee that the model does not change from the view of this
188      * thread while it is rendering (if the associated model is
189      * derived from {@code AbstractDocument}).  This enables the
190      * model to potentially be updated asynchronously.
191      *
192      * @param context context for the component being painted
193      * @param g the {@code Graphics} object used for painting
194      * @see #update(Graphics,JComponent)
195      */
paint(SynthContext context, Graphics g)196     protected void paint(SynthContext context, Graphics g) {
197         super.paint(g, getComponent());
198     }
199 
paintBackground(SynthContext context, Graphics g, JComponent c)200     void paintBackground(SynthContext context, Graphics g, JComponent c) {
201         context.getPainter().paintTextFieldBackground(context, g, 0, 0,
202                                                 c.getWidth(), c.getHeight());
203     }
204 
205     /**
206      * {@inheritDoc}
207      */
208     @Override
paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h)209     public void paintBorder(SynthContext context, Graphics g, int x,
210                             int y, int w, int h) {
211         context.getPainter().paintTextFieldBorder(context, g, x, y, w, h);
212     }
213 
214     /**
215      * {@inheritDoc}
216      * Overridden to do nothing.
217      */
218     @Override
paintBackground(Graphics g)219     protected void paintBackground(Graphics g) {
220         // Overriden to do nothing, all our painting is done from update/paint.
221     }
222 
223     /**
224      * This method gets called when a bound property is changed
225      * on the associated JTextComponent.  This is a hook
226      * which UI implementations may change to reflect how the
227      * UI displays bound properties of JTextComponent subclasses.
228      * This is implemented to do nothing (i.e. the response to
229      * properties in JTextComponent itself are handled prior
230      * to calling this method).
231      *
232      * @param evt the property change event
233      */
234     @Override
propertyChange(PropertyChangeEvent evt)235     protected void propertyChange(PropertyChangeEvent evt) {
236         if (evt.getPropertyName().equals("keymap")) {
237             if (evt.getNewValue() != null)
238             {
239                 updateKBAction = false;
240             } else {
241                 updateKBAction = true;
242             }
243         }
244         if (SynthLookAndFeel.shouldUpdateStyle(evt)) {
245             updateStyle((JTextComponent)evt.getSource(), updateKBAction);
246         }
247         super.propertyChange(evt);
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
253     @Override
installDefaults()254     protected void installDefaults() {
255         // Installs the text cursor on the component
256         super.installDefaults();
257         updateStyle(getComponent(), true);
258         getComponent().addFocusListener(handler);
259     }
260 
261     /**
262      * {@inheritDoc}
263      */
264     @Override
uninstallDefaults()265     protected void uninstallDefaults() {
266         SynthContext context = getContext(getComponent(), ENABLED);
267 
268         getComponent().putClientProperty("caretAspectRatio", null);
269         getComponent().removeFocusListener(handler);
270 
271         style.uninstallDefaults(context);
272         style = null;
273         super.uninstallDefaults();
274     }
275 
276     private final class Handler implements FocusListener {
focusGained(FocusEvent e)277         public void focusGained(FocusEvent e) {
278             getComponent().repaint();
279         }
280 
focusLost(FocusEvent e)281         public void focusLost(FocusEvent e) {
282             getComponent().repaint();
283         }
284     }
285 }
286