1 /*
   2  * Copyright (c) 2002, 2010, 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&trade;
  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 public class SynthTextFieldUI extends BasicTextFieldUI implements SynthUI {
  54     private Handler handler = new Handler();
  55     private SynthStyle style;
  56 
  57     /**
  58      * Creates a UI for a JTextField.
  59      *
  60      * @param c the text field
  61      * @return the UI object
  62      */
  63     public static ComponentUI createUI(JComponent c) {
  64         return new SynthTextFieldUI();
  65     }
  66 
  67     private void updateStyle(JTextComponent comp) {
  68         SynthContext context = getContext(comp, ENABLED);
  69         SynthStyle oldStyle = style;
  70 
  71         style = SynthLookAndFeel.updateStyle(context, this);
  72 
  73         if (style != oldStyle) {
  74             SynthTextFieldUI.updateStyle(comp, context, getPropertyPrefix());
  75 
  76             if (oldStyle != null) {
  77                 uninstallKeyboardActions();
  78                 installKeyboardActions();
  79             }
  80         }
  81         context.dispose();
  82     }
  83 
  84     static void updateStyle(JTextComponent comp, SynthContext context,
  85             String prefix) {
  86         SynthStyle style = context.getStyle();
  87 
  88         Color color = comp.getCaretColor();
  89         if (color == null || color instanceof UIResource) {
  90             comp.setCaretColor(
  91                 (Color)style.get(context, prefix + ".caretForeground"));
  92         }
  93 
  94         Color fg = comp.getForeground();
  95         if (fg == null || fg instanceof UIResource) {
  96             fg = style.getColorForState(context, ColorType.TEXT_FOREGROUND);
  97             if (fg != null) {
  98                 comp.setForeground(fg);
  99             }
 100         }
 101 
 102         Object ar = style.get(context, prefix + ".caretAspectRatio");
 103         if (ar instanceof Number) {
 104             comp.putClientProperty("caretAspectRatio", ar);
 105         }
 106 
 107         context.setComponentState(SELECTED | FOCUSED);
 108 
 109         Color s = comp.getSelectionColor();
 110         if (s == null || s instanceof UIResource) {
 111             comp.setSelectionColor(
 112                 style.getColor(context, ColorType.TEXT_BACKGROUND));
 113         }
 114 
 115         Color sfg = comp.getSelectedTextColor();
 116         if (sfg == null || sfg instanceof UIResource) {
 117             comp.setSelectedTextColor(
 118                 style.getColor(context, ColorType.TEXT_FOREGROUND));
 119         }
 120 
 121         context.setComponentState(DISABLED);
 122 
 123         Color dfg = comp.getDisabledTextColor();
 124         if (dfg == null || dfg instanceof UIResource) {
 125             comp.setDisabledTextColor(
 126                 style.getColor(context, ColorType.TEXT_FOREGROUND));
 127         }
 128 
 129         Insets margin = comp.getMargin();
 130         if (margin == null || margin instanceof UIResource) {
 131             margin = (Insets)style.get(context, prefix + ".margin");
 132 
 133             if (margin == null) {
 134                 // Some places assume margins are non-null.
 135                 margin = SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS;
 136             }
 137             comp.setMargin(margin);
 138         }
 139 
 140         Caret caret = comp.getCaret();
 141         if (caret instanceof UIResource) {
 142             Object o = style.get(context, prefix + ".caretBlinkRate");
 143             if (o != null && o instanceof Integer) {
 144                 Integer rate = (Integer)o;
 145                 caret.setBlinkRate(rate.intValue());
 146             }
 147         }
 148     }
 149 
 150     /**
 151      * {@inheritDoc}
 152      */
 153     @Override
 154     public SynthContext getContext(JComponent c) {
 155         return getContext(c, SynthLookAndFeel.getComponentState(c));
 156     }
 157 
 158     private SynthContext getContext(JComponent c, int state) {
 159         return SynthContext.getContext(SynthContext.class, c,
 160                     SynthLookAndFeel.getRegion(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
 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         context.dispose();
 183     }
 184 
 185     /**
 186      * Paints the specified component.
 187      * <p>This is routed to the {@link #paintSafely} method under
 188      * the guarantee that the model does not change from the view of this
 189      * thread while it is rendering (if the associated model is
 190      * derived from {@code AbstractDocument}).  This enables the
 191      * model to potentially be updated asynchronously.
 192      *
 193      * @param context context for the component being painted
 194      * @param g the {@code Graphics} object used for painting
 195      * @see #update(Graphics,JComponent)
 196      */
 197     protected void paint(SynthContext context, Graphics g) {
 198         super.paint(g, getComponent());
 199     }
 200 
 201     void paintBackground(SynthContext context, Graphics g, JComponent c) {
 202         context.getPainter().paintTextFieldBackground(context, g, 0, 0,
 203                                                 c.getWidth(), c.getHeight());
 204     }
 205 
 206     /**
 207      * {@inheritDoc}
 208      */
 209     @Override
 210     public void paintBorder(SynthContext context, Graphics g, int x,
 211                             int y, int w, int h) {
 212         context.getPainter().paintTextFieldBorder(context, g, x, y, w, h);
 213     }
 214 
 215     /**
 216      * {@inheritDoc}
 217      * Overridden to do nothing.
 218      */
 219     @Override
 220     protected void paintBackground(Graphics g) {
 221         // Overriden to do nothing, all our painting is done from update/paint.
 222     }
 223 
 224     /**
 225      * This method gets called when a bound property is changed
 226      * on the associated JTextComponent.  This is a hook
 227      * which UI implementations may change to reflect how the
 228      * UI displays bound properties of JTextComponent subclasses.
 229      * This is implemented to do nothing (i.e. the response to
 230      * properties in JTextComponent itself are handled prior
 231      * to calling this method).
 232      *
 233      * @param evt the property change event
 234      */
 235     @Override
 236     protected void propertyChange(PropertyChangeEvent evt) {
 237         if (SynthLookAndFeel.shouldUpdateStyle(evt)) {
 238             updateStyle((JTextComponent)evt.getSource());
 239         }
 240         super.propertyChange(evt);
 241     }
 242 
 243     /**
 244      * {@inheritDoc}
 245      */
 246     @Override
 247     protected void installDefaults() {
 248         // Installs the text cursor on the component
 249         super.installDefaults();
 250         updateStyle(getComponent());
 251         getComponent().addFocusListener(handler);
 252     }
 253 
 254     /**
 255      * {@inheritDoc}
 256      */
 257     @Override
 258     protected void uninstallDefaults() {
 259         SynthContext context = getContext(getComponent(), ENABLED);
 260 
 261         getComponent().putClientProperty("caretAspectRatio", null);
 262         getComponent().removeFocusListener(handler);
 263 
 264         style.uninstallDefaults(context);
 265         context.dispose();
 266         style = null;
 267         super.uninstallDefaults();
 268     }
 269 
 270     private final class Handler implements FocusListener {
 271         public void focusGained(FocusEvent e) {
 272             getComponent().repaint();
 273         }
 274 
 275         public void focusLost(FocusEvent e) {
 276             getComponent().repaint();
 277         }
 278     }
 279 }