Java tutorial
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved. Portions Copyrighted 2012 Daniel * Huss. * * The contents of this file are subject to the terms of either the GNU General Public License * Version 2 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, * the "License"). You may not use this file except in compliance with the License. You can obtain a * copy of the License at http://www.netbeans.org/cddl-gplv2.html or nbbuild/licenses/CDDL-GPL-2-CP. * See the License for the specific language governing permissions and limitations under the * License. When distributing the software, include this License Header Notice in each file and * include the License file at nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this particular file * as subject to the "Classpath" exception as provided by Sun in the GPL Version 2 section of the * License file that accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Contributor(s): * * The Original Software is NetBeans. The Initial Developer of the Original Software is Sun * Microsystems, Inc. Portions Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL or only the GPL Version 2, * indicate your decision by adding "[Contributor] elects to include this software in this * distribution under the [CDDL or GPL Version 2] license." If you do not indicate a single choice * of license, a recipient has the option to distribute your version of this file under either the * CDDL, the GPL Version 2 or to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL Version 2 license, then the * option applies only if the new code is made subject to such option by the copyright holder. */ package de.unentscheidbar.validation.swing.trigger; import java.util.Arrays; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import javax.annotation.Nullable; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.tuple.Pair; import com.google.common.collect.ImmutableList; import de.unentscheidbar.validation.internal.Methods; import de.unentscheidbar.validation.internal.Methods.MethodChain; final class SelectionChangeTrigger extends AbstractCoalescingTrigger<JComponent> { static final class SelectionChangeListener extends ComponentListener<JComponent> implements ListSelectionListener, TreeSelectionListener { SelectionChangeListener(AbstractCoalescingTrigger<JComponent> trigger, JComponent component) { super(trigger, component); } @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) fire(); } @Override public void valueChanged(TreeSelectionEvent e) { fire(); } } static final Trigger<JComponent> INSTANCE = new SelectionChangeTrigger(); private static final String[][] PROPERTY_HIERARCHIES = { { "getSelectionModel" }, { "getModel", "getSelectionModel" } }; private static final List<Pair<String, Class<?>>> SUPPORTED_ADD_METHODS = supportedAddMethods(); private static final List<Pair<String, Class<?>>> SUPPORTED_REMOVE_METHODS = supportedRemoveMethods(); private final Map<Object, SelectionChangeListener> listeners = new IdentityHashMap<>(); static boolean supports(Object classOrInstance) { if (classOrInstance instanceof Class<?>) { return supportsClass((Class<?>) classOrInstance); } else { return supportsInstance(classOrInstance); } } private static MethodChain getAddMethod(Class<?> clazz) { MethodChain result = null; for (String[] propHierarchy : PROPERTY_HIERARCHIES) { result = Methods.findMethod(clazz, SUPPORTED_ADD_METHODS, propHierarchy); if (result != null) break; } return result; } private static MethodChain getRemoveMethod(Class<?> clazz) { MethodChain result = null; for (String[] propHierarchy : PROPERTY_HIERARCHIES) { result = Methods.findMethod(clazz, SUPPORTED_REMOVE_METHODS, propHierarchy); if (result != null) break; } return result; } private static List<Pair<String, Class<?>>> supportedAddMethods() { return ImmutableList.of(Pair.<String, Class<?>>of("addListSelectionListener", ListSelectionListener.class), Pair.<String, Class<?>>of("addTreeSelectionListener", TreeSelectionListener.class)); } private static List<Pair<String, Class<?>>> supportedRemoveMethods() { return ImmutableList.of( Pair.<String, Class<?>>of("removeListSelectionListener", ListSelectionListener.class), Pair.<String, Class<?>>of("removeTreeSelectionListener", TreeSelectionListener.class)); } private static boolean supportsClass(Class<?> clazz) { final List<Class<?>> supportedClasses = Arrays.<Class<?>>asList(JTable.class, JList.class, JTree.class); for (Class<?> supportedClass : supportedClasses) { if (ClassUtils.isAssignable(clazz, supportedClass)) return true; } return getAddMethod(clazz) != null && getRemoveMethod(clazz) != null; } private static boolean supportsInstance(@Nullable Object o) { if (o == null) return false; return o instanceof JTable || o instanceof JList<?> || o instanceof JTree || supportsClass(o.getClass()); } @Override public void registerSelf(JComponent component) { if (!listeners.containsKey(component)) { listeners.put(component, doRegister(component)); } } @Override public void unregisterSelf(JComponent component) { SelectionChangeListener listener = listeners.get(component); if (listener != null) { doUnregister(component, listener); listeners.remove(component); } } private SelectionChangeListener doRegister(JComponent c) { SelectionChangeListener l = new SelectionChangeListener(this, c); if (c instanceof JTable) { ((JTable) c).getSelectionModel().addListSelectionListener(l); } else if (c instanceof JList<?>) { ((JList<?>) c).getSelectionModel().addListSelectionListener(l); } else if (c instanceof JTree) { ((JTree) c).addTreeSelectionListener(l); } else { MethodChain addListenerMethod = getAddMethod(c.getClass()); if (addListenerMethod == null) throw new UnsupportedClassException(c); addListenerMethod.invokeQuietly(c, l); } return l; } private void doUnregister(JComponent c, SelectionChangeListener l) { if (c instanceof JTable) { ((JTable) c).getSelectionModel().removeListSelectionListener(l); } else if (c instanceof JList<?>) { ((JList<?>) c).getSelectionModel().removeListSelectionListener(l); } else if (c instanceof JTree) { ((JTree) c).addTreeSelectionListener(l); } else { MethodChain removeListenerMethod = getRemoveMethod(c.getClass()); if (removeListenerMethod == null) throw new UnsupportedClassException(c); removeListenerMethod.invokeQuietly(c, l); } } }