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