alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.java.ui;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Arrays;
import java.util.LinkedList;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

import org.openide.NotifyDescriptor;

import org.openide.explorer.propertysheet.DefaultPropertyModel;
import org.openide.explorer.propertysheet.PropertyModel;
import org.openide.nodes.Index;
import org.openide.util.WeakListener;

/**
 * Serves as a base for Children, that present some indexed property's values.
 * The Children object watches a specified (indexed) property on a Bean and updates
 * accordingly. It also supports reorder-like manipulations on children, reflecting
 * those changes to the underlying bean as set-operations on the indexed property.
 */
public abstract class IndexedPropertyChildren extends Index.KeysChildren {
    /** Property model for getting/settings the property.
    */
    private PropertyModel model;

    /** Listener that updates the display from the underlying bean.
    */
    private PropertyChangeListener beanListener;

    /** States that changes from the bean should be ignored. Used to prevent
     * event loops between the bean and the children and unnecessary updates
     */
    boolean ignoreBeanChanges;

    /**
     * Initializes a new Children. It uses DefaultPropertyModel for communication
     * with the bean.
     */
    public IndexedPropertyChildren(Object bean, String propertyName) {
        this(new DefaultPropertyModel(bean, propertyName));
    }

    /**
     * Initializes a new Children instance with the given property model.
     */
    public IndexedPropertyChildren(PropertyModel m) {
        super(new LinkedList());
        this.model = m;
        
        if (!m.getPropertyType().isArray()) {
            throw new IllegalArgumentException("Property of array type expected."); //NOI18N
        }
    }

    /** Called when the children are about to be displayed.
        Attaches a listener to the target bean via property model and monitors its changes.
    */
    protected void addNotify() {
        model.addPropertyChangeListener(getBeanListener());
        refreshData();
    }

    /** Called after the children are removed from the display.
        Currently only removes the property listener. The method could as well omitted,
     * because it is called during node's finalize and the listener is Weak anyway.
    */
    protected void removeNotify() {
        model.removePropertyChangeListener(getBeanListener());
   }

    protected final PropertyChangeListener getBeanListener() {
        if (beanListener != null) {
            return beanListener;
        }
        return beanListener = createBeanListener();
    }

    /**
     * Creates a listener for the bean. This implementation creates a WeakListener
     * that watches for the property changes on the property passed to the Children
     * constructor and, if it arrives, invokes refresh()
     */
    protected PropertyChangeListener createBeanListener() {
        return new SourceListener();
    }

    /** Updates the children list from the source.
        This implementation obtains the current value from the property model and
        calls update().
    */
    protected final void refreshData() {
        Collection c;
        try {
            c = Arrays.asList((Object[])model.getValue());
        } catch (InvocationTargetException e) {
            // just ignore getter exceptions.
            return;
        }

        this.list.clear();
        this.list.addAll(c);
        update();
    }

    /**
     * Creates the array value from the given collection. The standard implementation
     * uses reflection to construct the returned array instance. The type of array
     * elements is extracted from the property model.
     */
    protected Object[] createValue(Collection value) {
        Class compType = model.getPropertyType().getComponentType();
        Object[] val = (Object[])java.lang.reflect.Array.newInstance(compType, value.size());
        return value.toArray(val);
    }

    /** Performs a reorder on the indexed property.
        This implementation reorders children's node list using superclass'
        reorder() method, then tries to update the bean with the new property value.
        If this fails, reorder updates the subnode list from the bean's current
        property value.
    */
    protected void reorder(int []permutation) {
        super.reorder(permutation);
        try {
            try {
                ignoreBeanChanges = true;
                Object[] value = createValue(list);
                model.setValue(value);
            } finally {
                ignoreBeanChanges = false;
            }
        } catch (InvocationTargetException e) {
            handleReorderException(e);
        }
    }

    /**
     * Reports a reorder error to the user. This (default) implementation does
     * nothing, it simply refreshes the display from the current bean's data.
     * @param InvocationTargetException thrown by the property model.
     */
    protected void handleReorderException(InvocationTargetException e) {
        refreshData();
    }

    /*************************************************************************/
    private class SourceListener implements PropertyChangeListener {
        public void propertyChange(PropertyChangeEvent evt) {
            if (PropertyModel.PROP_VALUE.equals(evt.getPropertyName())) {
//                IndexedPropertyChildren.this.refresh();
                IndexedPropertyChildren.this.refreshData();
            }
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.