de.unentscheidbar.validation.swing.trigger.SelectionChangeTrigger.java Source code

Java tutorial

Introduction

Here is the source code for de.unentscheidbar.validation.swing.trigger.SelectionChangeTrigger.java

Source

/*
 * 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);
        }
    }

}