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 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.beans.*; 31 32 import javax.swing.*; 33 import javax.swing.border.Border; 34 import javax.swing.event.MouseInputListener; 35 import javax.swing.plaf.ComponentUI; 36 import javax.swing.plaf.basic.BasicListUI; 37 38 import apple.laf.JRSUIConstants.*; 39 40 /** 41 * A Mac L&F implementation of JList 42 * 43 * All this does is look for a ThemeBorder and invalidate it when the focus changes 44 */ 45 public class AquaListUI extends BasicListUI { 46 public static ComponentUI createUI(final JComponent c) { 47 return new AquaListUI(); 48 } 49 50 /** 51 * Creates the focus listener to repaint the focus ring 52 */ 53 protected FocusListener createFocusListener() { 54 return new AquaListUI.FocusHandler(); 55 } 56 57 /** 58 * Creates a delegate that implements MouseInputListener. 59 */ 60 protected MouseInputListener createMouseInputListener() { 61 return new AquaListUI.MouseInputHandler(); 62 } 63 64 protected void installKeyboardActions() { 65 super.installKeyboardActions(); 66 list.getActionMap().put("aquaHome", new AquaHomeEndAction(true)); 67 list.getActionMap().put("aquaEnd", new AquaHomeEndAction(false)); 68 } 69 70 static class AquaHomeEndAction extends AbstractAction { 71 private boolean fHomeAction = false; 72 73 protected AquaHomeEndAction(final boolean isHomeAction) { 74 fHomeAction = isHomeAction; 75 } 76 77 /** 78 * For a Home action, scrolls to the top. Otherwise, scroll to the end. 79 */ 80 public void actionPerformed(final ActionEvent e) { 81 final JList list = (JList)e.getSource(); 82 83 if (fHomeAction) { 84 list.ensureIndexIsVisible(0); 85 } else { 86 final int size = list.getModel().getSize(); 87 list.ensureIndexIsVisible(size - 1); 88 } 89 } 90 } 91 92 /** 93 * This inner class is marked "public" due to a compiler bug. This class should be treated as a 94 * "protected" inner class. Instantiate it only within subclasses of BasicListUI. 95 */ 96 class FocusHandler extends BasicListUI.FocusHandler { 97 public void focusGained(final FocusEvent e) { 98 super.focusGained(e); 99 AquaBorder.repaintBorder(getComponent()); 100 } 101 102 public void focusLost(final FocusEvent e) { 103 super.focusLost(e); 104 AquaBorder.repaintBorder(getComponent()); 105 } 106 } 107 108 protected PropertyChangeListener createPropertyChangeListener() { 109 return new AquaPropertyChangeHandler(); 110 } 111 112 class AquaPropertyChangeHandler extends PropertyChangeHandler { 113 public void propertyChange(final PropertyChangeEvent e) { 114 final String prop = e.getPropertyName(); 115 if (AquaFocusHandler.FRAME_ACTIVE_PROPERTY.equals(prop)) { 116 AquaBorder.repaintBorder(getComponent()); 117 AquaFocusHandler.swapSelectionColors("List", getComponent(), e.getNewValue()); 118 } else { 119 super.propertyChange(e); 120 } 121 } 122 } 123 124 // TODO: Using default handler for now, need to handle cmd-key 125 126 // Replace the mouse event with one that returns the cmd-key state when asked 127 // for the control-key state, which super assumes is what everyone does to discontiguously extend selections 128 class MouseInputHandler extends BasicListUI.MouseInputHandler { 129 /*public void mousePressed(final MouseEvent e) { 130 super.mousePressed(new SelectionMouseEvent(e)); 131 } 132 public void mouseDragged(final MouseEvent e) { 133 super.mouseDragged(new SelectionMouseEvent(e)); 134 }*/ 135 } 136 137 JList getComponent() { 138 return list; 139 } 140 141 // this is used for blinking combobox popup selections when they are selected 142 protected void repaintCell(final Object value, final int selectedIndex, final boolean selected) { 143 final Rectangle rowBounds = getCellBounds(list, selectedIndex, selectedIndex); 144 if (rowBounds == null) return; 145 146 final ListCellRenderer renderer = list.getCellRenderer(); 147 if (renderer == null) return; 148 149 final Component rendererComponent = renderer.getListCellRendererComponent(list, value, selectedIndex, selected, true); 150 if (rendererComponent == null) return; 151 152 final AquaComboBoxRenderer aquaRenderer = renderer instanceof AquaComboBoxRenderer ? (AquaComboBoxRenderer)renderer : null; 153 if (aquaRenderer != null) aquaRenderer.setDrawCheckedItem(false); 154 rendererPane.paintComponent(list.getGraphics().create(), rendererComponent, list, rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height, true); 155 if (aquaRenderer != null) aquaRenderer.setDrawCheckedItem(true); 156 } 157 158 /* 159 Insert note on JIDESoft naughtiness 160 */ 161 public static Border getSourceListBackgroundPainter() { 162 final AquaBorder border = new ComponentPainter(); 163 border.painter.state.set(Widget.GRADIENT); 164 border.painter.state.set(Variant.GRADIENT_SIDE_BAR); 165 return border; 166 } 167 168 public static Border getSourceListSelectionBackgroundPainter() { 169 final AquaBorder border = new ComponentPainter(); 170 border.painter.state.set(Widget.GRADIENT); 171 border.painter.state.set(Variant.GRADIENT_SIDE_BAR_SELECTION); 172 return border; 173 } 174 175 public static Border getSourceListFocusedSelectionBackgroundPainter() { 176 final AquaBorder border = new ComponentPainter(); 177 border.painter.state.set(Widget.GRADIENT); 178 border.painter.state.set(Variant.GRADIENT_SIDE_BAR_FOCUSED_SELECTION); 179 return border; 180 } 181 182 public static Border getListEvenBackgroundPainter() { 183 final AquaBorder border = new ComponentPainter(); 184 border.painter.state.set(Widget.GRADIENT); 185 border.painter.state.set(Variant.GRADIENT_LIST_BACKGROUND_EVEN); 186 return border; 187 } 188 189 public static Border getListOddBackgroundPainter() { 190 final AquaBorder border = new ComponentPainter(); 191 border.painter.state.set(Widget.GRADIENT); 192 border.painter.state.set(Variant.GRADIENT_LIST_BACKGROUND_ODD); 193 return border; 194 } 195 196 static class ComponentPainter extends AquaBorder.Default { 197 public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h) { 198 final JComponent jc = c instanceof JComponent ? (JComponent)c : null; 199 if (jc != null && !AquaFocusHandler.isActive(jc)) { 200 painter.state.set(State.INACTIVE); 201 } else { 202 painter.state.set(State.ACTIVE); 203 } 204 super.paintBorder(c, g, x, y, w, h); 205 } 206 } 207 }