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 26package com.apple.laf; 27 28import java.awt.*; 29import java.awt.event.*; 30import java.awt.geom.*; 31 32import javax.swing.*; 33import javax.swing.border.Border; 34import javax.swing.plaf.*; 35import javax.swing.text.*; 36 37import com.apple.laf.AquaUtils.RecyclableSingleton; 38import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; 39 40public class AquaTextPasswordFieldUI extends AquaTextFieldUI { 41 private static final RecyclableSingleton<CapsLockSymbolPainter> capsLockPainter = new RecyclableSingletonFromDefaultConstructor<CapsLockSymbolPainter>(CapsLockSymbolPainter.class); 42 static CapsLockSymbolPainter getCapsLockPainter() { 43 return capsLockPainter.get(); 44 } 45 46 public static ComponentUI createUI(final JComponent c) { 47 return new AquaTextPasswordFieldUI(); 48 } 49 50 @Override 51 protected String getPropertyPrefix() { 52 return "PasswordField"; 53 } 54 55 @Override 56 public View create(final Element elem) { 57 return new AquaPasswordView(elem); 58 } 59 60 @Override 61 protected void installListeners() { 62 super.installListeners(); 63 getComponent().addKeyListener(getCapsLockPainter()); 64 } 65 66 @Override 67 protected void uninstallListeners() { 68 getComponent().removeKeyListener(getCapsLockPainter()); 69 super.uninstallListeners(); 70 } 71 72 @Override 73 protected void paintBackgroundSafely(final Graphics g) { 74 super.paintBackgroundSafely(g); 75 76 final JTextComponent component = getComponent(); 77 if (component == null) return; 78 if (!component.isFocusOwner()) return; 79 80 final boolean capsLockDown = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK); 81 if (!capsLockDown) return; 82 83 final Rectangle bounds = component.getBounds(); 84 getCapsLockPainter().paintBorder(component, g, bounds.x, bounds.y, bounds.width, bounds.height); 85 } 86 87 protected class AquaPasswordView extends PasswordView { 88 public AquaPasswordView(final Element elem) { 89 super(elem); 90 setupDefaultEchoCharacter(); 91 } 92 93 protected void setupDefaultEchoCharacter() { 94 // this allows us to change the echo character in CoreAquaLookAndFeel.java 95 final Character echoChar = (Character)UIManager.getDefaults().get(getPropertyPrefix() + ".echoChar"); 96 if (echoChar != null) { 97 LookAndFeel.installProperty(getComponent(), "echoChar", echoChar); 98 } 99 } 100 } 101 102 static class CapsLockSymbolPainter extends KeyAdapter implements Border, UIResource { 103 protected Shape capsLockShape; 104 protected Shape getCapsLockShape() { 105 if (capsLockShape != null) return capsLockShape; 106 107 final RoundRectangle2D rect = new RoundRectangle2D.Double(0.5, 0.5, 16, 16, 8, 8); 108 final GeneralPath shape = new GeneralPath(rect); 109 shape.setWindingRule(Path2D.WIND_EVEN_ODD); 110 111 // arrow 112 shape.moveTo( 8.50, 2.00); 113 shape.lineTo( 4.00, 7.00); 114 shape.lineTo( 6.25, 7.00); 115 shape.lineTo( 6.25, 10.25); 116 shape.lineTo(10.75, 10.25); 117 shape.lineTo(10.75, 7.00); 118 shape.lineTo(13.00, 7.00); 119 shape.lineTo( 8.50, 2.00); 120 121 // base line 122 shape.moveTo(10.75, 12.00); 123 shape.lineTo( 6.25, 12.00); 124 shape.lineTo( 6.25, 14.25); 125 shape.lineTo(10.75, 14.25); 126 shape.lineTo(10.75, 12.00); 127 128 return capsLockShape = shape; 129 } 130 131 @Override 132 public Insets getBorderInsets(final Component c) { 133 return new Insets(0, 0, 0, 0); 134 } 135 136 @Override 137 public boolean isBorderOpaque() { 138 return false; 139 } 140 141 @Override 142 public void paintBorder(final Component c, Graphics g, final int x, final int y, final int width, final int height) { 143 g = g.create(width - 23, height / 2 - 8, 18, 18); 144 145 g.setColor(UIManager.getColor("PasswordField.capsLockIconColor")); 146 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 147 ((Graphics2D)g).fill(getCapsLockShape()); 148 g.dispose(); 149 } 150 151 @Override 152 public void keyPressed(final KeyEvent e) { 153 update(e); 154 } 155 156 @Override 157 public void keyReleased(final KeyEvent e) { 158 update(e); 159 } 160 161 void update(final KeyEvent e) { 162 if (KeyEvent.VK_CAPS_LOCK != e.getKeyCode()) return; 163 e.getComponent().repaint(); 164 } 165 } 166} 167