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.beans.*; 31 32import javax.swing.*; 33import javax.swing.plaf.UIResource; 34 35/** 36 * This class is used by the text components, AquaEditorPaneUI, AquaTextAreaUI, AquaTextFieldUI and AquaTextPaneUI to control painting of the 37 * component's border. NOTE: It is assumed that this handler is added to components that extend JComponent. 38 */ 39public class AquaFocusHandler implements FocusListener, PropertyChangeListener { 40 // Flag to help focusGained() determine whether the origin focus loss was due to a temporary focus loss or not. 41 private boolean wasTemporary = false; 42 43 // Flag to track when a border needs a repaint due to a window becoming activate/inactive. 44 private boolean repaintBorder = false; 45 46 protected static final String FRAME_ACTIVE_PROPERTY = "Frame.active"; 47 48 public void focusGained(final FocusEvent ev) { 49 // If we gained focus and it wasn't due to a previous temporary focus loss 50 // or the frame became active again, then repaint the border on the component. 51 if (!wasTemporary || repaintBorder) { 52 AquaBorder.repaintBorder((JComponent)ev.getSource()); 53 repaintBorder = false; 54 } 55 wasTemporary = false; 56 } 57 58 public void focusLost(final FocusEvent ev) { 59 wasTemporary = ev.isTemporary(); 60 61 // If we lost focus due to a permanent focus loss then repaint the border on the component. 62 if (!wasTemporary) { 63 AquaBorder.repaintBorder((JComponent)ev.getSource()); 64 } 65 } 66 67 public void propertyChange(final PropertyChangeEvent ev) { 68 if (!FRAME_ACTIVE_PROPERTY.equals(ev.getPropertyName())) return; 69 70 if (Boolean.TRUE.equals(ev.getNewValue())) { 71 // The FRAME_ACTIVE_PROPERTY change event is sent before a component gains focus. 72 // We set a flag to help the focusGained() determine when they should be repainting 73 // the components focus. 74 repaintBorder = true; 75 } else if (wasTemporary) { 76 // The FRAME_ACTIVE_PROPERTY change event is sent after a component loses focus. 77 // We use the wasTemporary flag to determine if we need to repaint the border. 78 AquaBorder.repaintBorder((JComponent)ev.getSource()); 79 } 80 } 81 82 protected static boolean isActive(final JComponent c) { 83 if (c == null) return true; 84 final Object activeObj = c.getClientProperty(AquaFocusHandler.FRAME_ACTIVE_PROPERTY); 85 if (Boolean.FALSE.equals(activeObj)) return false; 86 return true; 87 } 88 89 static final PropertyChangeListener REPAINT_LISTENER = new PropertyChangeListener() { 90 public void propertyChange(final PropertyChangeEvent evt) { 91 final Object source = evt.getSource(); 92 if (source instanceof JComponent) { 93 ((JComponent)source).repaint(); 94 } 95 } 96 }; 97 98 protected static void install(final JComponent c) { 99 c.addPropertyChangeListener(FRAME_ACTIVE_PROPERTY, REPAINT_LISTENER); 100 } 101 102 protected static void uninstall(final JComponent c) { 103 c.removePropertyChangeListener(FRAME_ACTIVE_PROPERTY, REPAINT_LISTENER); 104 } 105 106 static void swapSelectionColors(final String prefix, final JTree c, final Object value) { 107 // <rdar://problem/8166173> JTree: selection color does not dim when window becomes inactive 108 // TODO inject our colors into the DefaultTreeCellRenderer 109 } 110 111 static void swapSelectionColors(final String prefix, final JTable c, final Object value) { 112 if (!isComponentValid(c)) return; 113 114 final Color bg = c.getSelectionBackground(); 115 final Color fg = c.getSelectionForeground(); 116 if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return; 117 118 if (Boolean.FALSE.equals(value)) { 119 setSelectionColors(c, "Table.selectionInactiveForeground", "Table.selectionInactiveBackground"); 120 return; 121 } 122 123 if (Boolean.TRUE.equals(value)) { 124 setSelectionColors(c, "Table.selectionForeground", "Table.selectionBackground"); 125 return; 126 } 127 } 128 129 static void setSelectionColors(final JTable c, final String fgName, final String bgName) { 130 c.setSelectionForeground(UIManager.getColor(fgName)); 131 c.setSelectionBackground(UIManager.getColor(bgName)); 132 } 133 134 static void swapSelectionColors(final String prefix, final JList<?> c, final Object value) { 135 if (!isComponentValid(c)) return; 136 137 final Color bg = c.getSelectionBackground(); 138 final Color fg = c.getSelectionForeground(); 139 if (!(bg instanceof UIResource) || !(fg instanceof UIResource)) return; 140 141 if (Boolean.FALSE.equals(value)) { 142 setSelectionColors(c, "List.selectionInactiveForeground", "List.selectionInactiveBackground"); 143 return; 144 } 145 146 if (Boolean.TRUE.equals(value)) { 147 setSelectionColors(c, "List.selectionForeground", "List.selectionBackground"); 148 return; 149 } 150 } 151 152 static void setSelectionColors(final JList<?> c, final String fgName, final String bgName) { 153 c.setSelectionForeground(UIManager.getColor(fgName)); 154 c.setSelectionBackground(UIManager.getColor(bgName)); 155 } 156 157 static boolean isComponentValid(final JComponent c) { 158 if (c == null) return false; 159 final Window window = SwingUtilities.getWindowAncestor(c); 160 if (window == null) return false; 161 return true; 162 } 163} 164