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&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 @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      */
  65     public static ComponentUI createUI(JComponent c) {
  66         return new SynthTextFieldUI();
  67     }
  68 
  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 
  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
 155     public SynthContext getContext(JComponent c) {
 156         return getContext(c, SynthLookAndFeel.getComponentState(c));
 157     }
 158 
 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
 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      */
 196     protected void paint(SynthContext context, Graphics g) {
 197         super.paint(g, getComponent());
 198     }
 199 
 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
 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
 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
 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
 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
 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 {
 277         public void focusGained(FocusEvent e) {
 278             getComponent().repaint();
 279         }
 280 
 281         public void focusLost(FocusEvent e) {
 282             getComponent().repaint();
 283         }
 284     }
 285 }