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.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Arrays; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.tuple.Pair; import de.unentscheidbar.validation.internal.Methods; import de.unentscheidbar.validation.internal.Methods.MethodChain; final class ChangeTrigger extends AbstractCoalescingTrigger<JComponent> { static final class ComponentChangeListener extends ComponentListener<JComponent> implements ChangeListener { ComponentChangeListener(AbstractCoalescingTrigger<JComponent> trigger, JComponent component) { super(trigger, component); } @Override public void stateChanged(ChangeEvent e) { fire(); } } static final class ItemChangeListener extends ComponentListener<JComponent> implements ItemListener { ItemChangeListener(AbstractCoalescingTrigger<JComponent> trigger, JComponent component) { super(trigger, component); } @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { fire(); } } } static final class TableChangeListener extends ComponentListener<JComponent> implements TableModelListener { TableChangeListener(AbstractCoalescingTrigger<JComponent> trigger, JComponent component) { super(trigger, component); } @Override public void tableChanged(TableModelEvent e) { fire(); } } public static final Trigger<JComponent> INSTANCE = new ChangeTrigger(); private static final Pair<String, Class<?>> ADD_METHOD = Pair.<String, Class<?>>of("addChangeListener", ChangeListener.class); private static final String[] PROPERTY_HIERARCHY = { "model" }; private static final Pair<String, Class<?>> REMOVE_METHOD = Pair.<String, Class<?>>of("removeChangeListener", ChangeListener.class); public static boolean supports(Object classOrInstance) { if (classOrInstance instanceof Class<?>) { return supportsClass((Class<?>) classOrInstance); } else { return supportsInstance(classOrInstance); } } private static MethodChain getAddMethod(Class<?> clazz) { return Methods.findMethod(clazz, ADD_METHOD, PROPERTY_HIERARCHY); } private static MethodChain getRemoveMethod(Class<?> clazz) { return Methods.findMethod(clazz, REMOVE_METHOD, PROPERTY_HIERARCHY); } private static boolean supportsClass(Class<?> clazz) { List<Class<?>> supportedClasses = Arrays.<Class<?>>asList(JComboBox.class, JRadioButton.class, JCheckBox.class, JColorChooser.class, JSlider.class, JSpinner.class, JTable.class); for (Class<?> supportedClass : supportedClasses) { if (ClassUtils.isAssignable(clazz, supportedClass)) return true; } return getAddMethod(clazz) != null && getRemoveMethod(clazz) != null; } private static boolean supportsInstance(Object o) { if (o == null) return false; else return o instanceof JComboBox<?> || o instanceof JRadioButton || o instanceof JCheckBox || o instanceof JColorChooser || o instanceof JSlider || o instanceof JSpinner || o instanceof JTable || supportsClass(o.getClass()); } private final Map<Object, Object> listeners = new IdentityHashMap<>(); @Override public void registerSelf(JComponent component) { if (!listeners.containsKey(component)) { listeners.put(component, doRegister(component)); } } @Override public void unregisterSelf(JComponent component) { Object listener = listeners.get(component); if (listener != null) { doUnregister(component, listener); listeners.remove(component); } } private Object doRegister(JComponent c) { ComponentChangeListener l = new ComponentChangeListener(this, c); Object result = l; if (c instanceof JComboBox<?>) { ItemListener il = new ItemChangeListener(this, c); result = il; ((JComboBox<?>) c).addItemListener(il); } else if (c instanceof JRadioButton) { ItemListener il = new ItemChangeListener(this, c); result = il; ((JRadioButton) c).addItemListener(il); } else if (c instanceof JCheckBox) { ItemListener il = new ItemChangeListener(this, c); result = il; ((JCheckBox) c).addItemListener(il); } else if (c instanceof JColorChooser) { ((JColorChooser) c).getSelectionModel().addChangeListener(l); } else if (c instanceof JSlider) { ((JSlider) c).addChangeListener(l); } else if (c instanceof JSpinner) { ((JSpinner) c).addChangeListener(l); } else if (c instanceof JTable) { TableChangeListener tl = new TableChangeListener(this, c); result = tl; ((JTable) c).getModel().addTableModelListener(tl); } else { MethodChain addChangeListenerMethod = getAddMethod(c.getClass()); if (addChangeListenerMethod == null) throw new UnsupportedClassException(c); addChangeListenerMethod.invokeQuietly(c, l); } return result; } private void doUnregister(JComponent c, Object l) { if (c instanceof JComboBox<?>) { ((JComboBox<?>) c).removeItemListener((ItemListener) l); } else if (c instanceof JColorChooser) { ((JColorChooser) c).getSelectionModel().removeChangeListener((ChangeListener) l); } else if (c instanceof JSlider) { ((JSlider) c).addChangeListener((ChangeListener) l); } else if (c instanceof JSpinner) { ((JSpinner) c).addChangeListener((ChangeListener) l); } else if (c instanceof JTable) { ((JTable) c).getModel().addTableModelListener((TableModelListener) l); } else { MethodChain removeChangeListenerMethod = getRemoveMethod(c.getClass()); if (removeChangeListenerMethod == null) throw new UnsupportedClassException(c); removeChangeListenerMethod.invokeQuietly(c, (ChangeListener) l); } } }