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 { createUI(final JComponent c)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 */ createFocusListener()53 protected FocusListener createFocusListener() { 54 return new AquaListUI.FocusHandler(); 55 } 56 57 /** 58 * Creates a delegate that implements MouseInputListener. 59 */ createMouseInputListener()60 protected MouseInputListener createMouseInputListener() { 61 return new AquaListUI.MouseInputHandler(); 62 } 63 installKeyboardActions()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 AquaHomeEndAction(final boolean isHomeAction)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 */ actionPerformed(final ActionEvent e)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 { focusGained(final FocusEvent e)97 public void focusGained(final FocusEvent e) { 98 super.focusGained(e); 99 AquaBorder.repaintBorder(getComponent()); 100 } 101 focusLost(final FocusEvent e)102 public void focusLost(final FocusEvent e) { 103 super.focusLost(e); 104 AquaBorder.repaintBorder(getComponent()); 105 } 106 } 107 createPropertyChangeListener()108 protected PropertyChangeListener createPropertyChangeListener() { 109 return new AquaPropertyChangeHandler(); 110 } 111 112 class AquaPropertyChangeHandler extends PropertyChangeHandler { propertyChange(final PropertyChangeEvent e)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 getComponent()137 JList getComponent() { 138 return list; 139 } 140 141 // this is used for blinking combobox popup selections when they are selected repaintCell(final Object value, final int selectedIndex, final boolean 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 */ getSourceListBackgroundPainter()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 getSourceListSelectionBackgroundPainter()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 getSourceListFocusedSelectionBackgroundPainter()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 getListEvenBackgroundPainter()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 getListOddBackgroundPainter()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 { paintBorder(final Component c, final Graphics g, final int x, final int y, final int w, final int h)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 } 208