Path: blob/master/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java
41153 views
/*1* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.lwawt;2627import java.awt.Component;28import java.awt.Dimension;29import java.awt.Font;30import java.awt.Insets;31import java.awt.List;32import java.awt.Point;33import java.awt.SystemColor;34import java.awt.event.ActionEvent;35import java.awt.event.ItemEvent;36import java.awt.event.KeyEvent;37import java.awt.event.MouseEvent;38import java.awt.peer.ListPeer;39import java.util.Arrays;4041import javax.swing.DefaultListModel;42import javax.swing.JList;43import javax.swing.JScrollBar;44import javax.swing.JScrollPane;45import javax.swing.JViewport;46import javax.swing.ListCellRenderer;47import javax.swing.ListSelectionModel;48import javax.swing.event.ListSelectionEvent;49import javax.swing.event.ListSelectionListener;5051/**52* Lightweight implementation of {@link ListPeer}. Delegates most of the work to53* the {@link JList}, which is placed inside {@link JScrollPane}.54*/55final class LWListPeer extends LWComponentPeer<List, LWListPeer.ScrollableJList>56implements ListPeer {5758/**59* The default number of visible rows.60*/61private static final int DEFAULT_VISIBLE_ROWS = 4; // From java.awt.List,6263/**64* This text is used for cell bounds calculation.65*/66private static final String TEXT = "0123456789abcde";6768LWListPeer(final List target, final PlatformComponent platformComponent) {69super(target, platformComponent);70if (!getTarget().isBackgroundSet()) {71getTarget().setBackground(SystemColor.text);72}73}7475@Override76ScrollableJList createDelegate() {77return new ScrollableJList();78}7980@Override81void initializeImpl() {82super.initializeImpl();83setMultipleMode(getTarget().isMultipleMode());84makeVisible(getTarget().getVisibleIndex());85final int[] selectedIndices = getTarget().getSelectedIndexes();86synchronized (getDelegateLock()) {87getDelegate().setSkipStateChangedEvent(true);88getDelegate().getView().setSelectedIndices(selectedIndices);89getDelegate().setSkipStateChangedEvent(false);90}91}9293@Override94public boolean isFocusable() {95return true;96}9798@Override99Component getDelegateFocusOwner() {100return getDelegate().getView();101}102103@Override104public int[] getSelectedIndexes() {105synchronized (getDelegateLock()) {106return getDelegate().getView().getSelectedIndices();107}108}109110@Override111public void add(final String item, final int index) {112synchronized (getDelegateLock()) {113getDelegate().getModel().add(index, item);114revalidate();115}116}117118@Override119public void delItems(final int start, final int end) {120synchronized (getDelegateLock()) {121getDelegate().getModel().removeRange(start, end);122revalidate();123}124}125126@Override127public void removeAll() {128synchronized (getDelegateLock()) {129getDelegate().getModel().removeAllElements();130revalidate();131}132}133134@Override135public void select(final int index) {136synchronized (getDelegateLock()) {137getDelegate().setSkipStateChangedEvent(true);138getDelegate().getView().setSelectedIndex(index);139getDelegate().setSkipStateChangedEvent(false);140}141}142143@Override144public void deselect(final int index) {145synchronized (getDelegateLock()) {146getDelegate().getView().getSelectionModel().147removeSelectionInterval(index, index);148}149}150151@Override152public void makeVisible(final int index) {153synchronized (getDelegateLock()) {154getDelegate().getView().ensureIndexIsVisible(index);155}156}157158@Override159public void setMultipleMode(final boolean m) {160synchronized (getDelegateLock()) {161getDelegate().getView().setSelectionMode(m ?162ListSelectionModel.MULTIPLE_INTERVAL_SELECTION163: ListSelectionModel.SINGLE_SELECTION);164}165}166167@Override168public Dimension getPreferredSize() {169return getMinimumSize();170}171172@Override173public Dimension getMinimumSize() {174return getMinimumSize(DEFAULT_VISIBLE_ROWS);175}176177@Override178public Dimension getPreferredSize(final int rows) {179return getMinimumSize(rows);180}181182@Override183public Dimension getMinimumSize(final int rows) {184synchronized (getDelegateLock()) {185final Dimension size = getCellSize();186size.height *= rows;187// Always take vertical scrollbar into account.188final JScrollBar vbar = getDelegate().getVerticalScrollBar();189size.width += vbar != null ? vbar.getMinimumSize().width : 0;190// JScrollPane and JList insets191final Insets pi = getDelegate().getInsets();192final Insets vi = getDelegate().getView().getInsets();193size.width += pi.left + pi.right + vi.left + vi.right;194size.height += pi.top + pi.bottom + vi.top + vi.bottom;195return size;196}197}198199private Dimension getCellSize() {200final JList<String> jList = getDelegate().getView();201final ListCellRenderer<? super String> cr = jList.getCellRenderer();202final Component cell = cr.getListCellRendererComponent(jList, TEXT, 0,203false, false);204return cell.getPreferredSize();205}206207private void revalidate() {208synchronized (getDelegateLock()) {209getDelegate().getView().invalidate();210getDelegate().validate();211}212}213214@SuppressWarnings("serial")// Safe: outer class is non-serializable.215final class ScrollableJList extends JScrollPane implements ListSelectionListener {216217private boolean skipStateChangedEvent;218219private final DefaultListModel<String> model =220new DefaultListModel<String>() {221@Override222public void add(final int index, final String element) {223if (index == -1) {224addElement(element);225} else {226super.add(index, element);227}228}229};230231private int[] oldSelectedIndices = new int[0];232233ScrollableJList() {234getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);235final JList<String> list = new JListDelegate();236list.addListSelectionListener(this);237238getViewport().setView(list);239240// Pull the items from the target.241final String[] items = getTarget().getItems();242for (int i = 0; i < items.length; i++) {243model.add(i, items[i]);244}245}246247public boolean isSkipStateChangedEvent() {248return skipStateChangedEvent;249}250251public void setSkipStateChangedEvent(boolean skipStateChangedEvent) {252this.skipStateChangedEvent = skipStateChangedEvent;253}254255@Override256@SuppressWarnings("unchecked")257public void valueChanged(final ListSelectionEvent e) {258if (!e.getValueIsAdjusting() && !isSkipStateChangedEvent()) {259final JList<?> source = (JList<?>) e.getSource();260for(int i = 0 ; i < source.getModel().getSize(); i++) {261262final boolean wasSelected = Arrays.binarySearch(oldSelectedIndices, i) >= 0;263final boolean isSelected = source.isSelectedIndex(i);264265if (wasSelected == isSelected) {266continue;267}268269final int state = !wasSelected && isSelected ? ItemEvent.SELECTED: ItemEvent.DESELECTED;270271LWListPeer.this.postEvent(new ItemEvent(getTarget(), ItemEvent.ITEM_STATE_CHANGED,272i, state));273}274oldSelectedIndices = source.getSelectedIndices();275}276}277278@SuppressWarnings("unchecked")279public JList<String> getView() {280return (JList<String>) getViewport().getView();281}282283public DefaultListModel<String> getModel() {284return model;285}286287@Override288public void setEnabled(final boolean enabled) {289getView().setEnabled(enabled);290super.setEnabled(enabled);291}292293@Override294public void setOpaque(final boolean isOpaque) {295super.setOpaque(isOpaque);296if (getView() != null) {297getView().setOpaque(isOpaque);298}299}300301@Override302public void setFont(Font font) {303super.setFont(font);304if (getView() != null) {305getView().setFont(font);306LWListPeer.this.revalidate();307}308}309310private final class JListDelegate extends JList<String> {311312JListDelegate() {313super(model);314}315316@Override317public boolean hasFocus() {318return getTarget().hasFocus();319}320321@Override322@SuppressWarnings("deprecation")323protected void processMouseEvent(final MouseEvent e) {324super.processMouseEvent(e);325if (e.getID() == MouseEvent.MOUSE_CLICKED && e.getClickCount() == 2) {326final int index = locationToIndex(e.getPoint());327if (0 <= index && index < getModel().getSize()) {328LWListPeer.this.postEvent(new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED,329getModel().getElementAt(index), e.getWhen(), e.getModifiers()));330}331}332}333334@Override335@SuppressWarnings("deprecation")336protected void processKeyEvent(final KeyEvent e) {337super.processKeyEvent(e);338if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_ENTER) {339final String selectedValue = getSelectedValue();340if(selectedValue != null){341LWListPeer.this.postEvent(new ActionEvent(getTarget(), ActionEvent.ACTION_PERFORMED,342selectedValue, e.getWhen(), e.getModifiers()));343}344}345}346347//Needed for Autoscroller.348@Override349public Point getLocationOnScreen() {350return LWListPeer.this.getLocationOnScreen();351}352}353}354}355356357