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-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.openide.explorer.propertysheet;

import java.util.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

import org.openide.ErrorManager;
import org.openide.nodes.*;
import org.openide.util.*;

/** 
 * A node used by PropertySheet to display common properties of
 * more nodes.
 * @author David Strupl
 */
final class ProxyNode extends AbstractNode {

    private Node[] original;
    private NodeListener pcl;
    
    ProxyNode(Node[] original) {
        super (Children.LEAF);
        this.original = original;
        pcl = new NodeAdapter() {
            public void propertyChange(PropertyChangeEvent pce) {
                String nm = pce.getPropertyName();
                if (PROP_COOKIE.equals(nm)) {
                    fireCookieChange();
                } else if (PROP_DISPLAY_NAME.equals(nm)) {
                    displayName = null;
                    fireDisplayNameChange((String)pce.getOldValue(), getDisplayName());
                } else if (PROP_ICON.equals(nm)) {
                    fireIconChange();
                } else if (PROP_OPENED_ICON.equals(nm)) {
                    fireOpenedIconChange();
                } else if (PROP_NAME.equals(nm)) {
                    fireNameChange((String) pce.getOldValue(), getName());
                } else if (PROP_PROPERTY_SETS.equals(nm)) {
                    PropertySet[] old = getPropertySets();
                    setSheet(createSheet());
                    firePropertySetsChange(old, getPropertySets());
                } else if (PROP_SHORT_DESCRIPTION.equals(nm)) {
                    fireShortDescriptionChange((String) pce.getOldValue(), getShortDescription());
                } else if (PROP_LEAF.equals(nm)) {
                    //Not interesting to property sheet
                } else if (PROP_PARENT_NODE.equals(nm)) {
                    //Not interesting to property sheet
                } else {
                    firePropertyChange(pce.getPropertyName(), pce.getOldValue(), pce.getNewValue());
                }
            }
            public void nodeDestroyed (NodeEvent ev) {
                int idx = Arrays.asList(ProxyNode.this.original).indexOf ((Node) ev.getSource());
                if (idx != -1) {
                    HashSet set = new HashSet (Arrays.asList(ProxyNode.this.original));
                    set.remove(ev.getSource());
                    ProxyNode.this.original = (Node[]) set.toArray(new Node[0]);
                    if (set.size() == 0) {
                        ProxyNode.this.fireNodeDestroyed();
                    }
                }
            }
        };
        for (int i = 0; i < original.length; i++) {
            original[i].addPropertyChangeListener(
                org.openide.util.WeakListeners.propertyChange(pcl, original[i]));
            original[i].addNodeListener ((NodeListener) 
                org.openide.util.WeakListeners.create (NodeListener.class, pcl, original[i]));
        }
    }

    public HelpCtx getHelpCtx () {
        for (int i = 0; i < original.length; i++) {
            if (original[i].getHelpCtx() != HelpCtx.DEFAULT_HELP) {
                return original[i].getHelpCtx();
            }
        }
        return HelpCtx.DEFAULT_HELP;
    }

    public Node cloneNode () {
        return new ProxyNode(original);
    }

    protected Sheet createSheet () {
	Sheet sheet = super.createSheet ();
        Sheet.Set[] computedSet = computePropertySets();
        for (int i = 0; i < computedSet.length; i++) {
            sheet.put(computedSet[i]);
       }
        return sheet;
    }
    
    /** */
    Node[] getOriginalNodes() {
        return original;
    }
    
    String displayName = null;
    public String getDisplayName () {
        if (displayName == null) {
            //Issue 40821, don't display extremely long names, they make
            //the property sheet huge if opened in a window
            displayName = getConcatenatedName(MAX_NAMES);
        }
        return displayName;
    }
    
    private String getConcatenatedName(int limit) {
        Node[] n = getOriginalNodes();
        StringBuffer name = new StringBuffer();
        String delim = NbBundle.getMessage (ProxyNode.class, 
            "CTL_List_Delimiter"); //NOI18N
        for (int i=0; i < n.length; i++) {
            name.append (n[i].getDisplayName());
            if (i != n.length -1) {
                name.append (delim);
            }
            if (i >= limit && i != n.length -1) {
                name.append(NbBundle.getMessage(ProxyNode.class, "MSG_ELLIPSIS"));
                break;
            }
        }
        return name.toString();
    }
    
    private String shortDescription = null;
    private static final int MAX_NAMES=2;
    public String getShortDescription () {
        if (getOriginalNodes().length < MAX_NAMES) {
            return NbBundle.getMessage (ProxyNode.class, 
                "CTL_Multiple_Selection"); //NOI18N
        } else {
            if (shortDescription == null) {
                shortDescription = getConcatenatedName(Integer.MAX_VALUE);
            }
            return shortDescription;
        }
    }
    
    /** Computes intersection of tabs and intersection
     * of properties in those tabs.
     */
    private Sheet.Set[] computePropertySets() {
        if (original.length > 0) {
            Node.PropertySet []firstSet = original[0].getPropertySets();
            java.util.Set sheets = new HashSet(
                Arrays.asList(firstSet));
            
            // compute intersection of all Node.PropertySets for given nodes
            for (int i = 1; i < original.length; i++) {
                sheets.retainAll(
                    new HashSet(Arrays.asList(original[i].getPropertySets())));
            }
            
            ArrayList resultSheets = new ArrayList(sheets.size());
            // now for all resulting sheets take common properties
            for (int i = 0; i < firstSet.length; i++) {
                if (! sheets.contains(firstSet[i]) || firstSet[i].isHidden ()) {
                    continue;
                }
                Node.PropertySet current = firstSet[i];

                // creates an empty Sheet.Set with same names as current
                Sheet.Set res = new Sheet.Set();
                res.setName(current.getName());
                res.setDisplayName(current.getDisplayName());
                res.setShortDescription(current.getShortDescription());

                String tabName = (String) current.getValue("tabName"); //NOI18N
                if (tabName != null) {
                    res.setValue ("tabName", tabName); //NOI18N
                }

                java.util.Set props = new HashSet(
                    Arrays.asList(current.getProperties()));
                
                String propsHelpID = null;
                // intersection of properties from the corresponding tabs
                for (int j = 0; j < original.length; j++) {
                    Node.PropertySet[] p = original[j].getPropertySets();
                    for (int k = 0; k < p.length; k++) {
                        if (current.getName().equals(p[k].getName())) {
                            props.retainAll(new HashSet(
                                Arrays.asList(p[k].getProperties())));
                        }
                    }
                }
                Node.Property []p = current.getProperties();
                for (int j = 0; j < p.length; j++) {
                    if (! props.contains(p[j])) {
                        continue;
                    }
                    if (p[j].isHidden ()) {
                        continue;
                    }
                    ProxyProperty pp = createProxyProperty(
                        p[j].getName(),
                        res.getName()
                    );
                    res.put(pp);
                }
                resultSheets.add(res);
            }
            
            return (Sheet.Set[])resultSheets.toArray(
                new Sheet.Set[resultSheets.size()]);
        }
        return new Sheet.Set[0];
    }

    /** Finds properties in original with specified
     * name in all tabs and constructs a ProxyProperty instance.
     */
    private ProxyProperty createProxyProperty(String propName, String setName) {
        Node.Property []arr = new Node.Property[original.length];
        for (int i = 0; i < original.length; i++) {
            Node.PropertySet[] p = original[i].getPropertySets();
            for (int j = 0; j < p.length; j++) {
                if (p[j].getName().equals(setName)) {
                    Node.Property[] np = p[j].getProperties();
                    for (int k = 0; k < np.length; k++) {
                        if (np[k].getName().equals(propName)) {
                            arr[i] = np[k];
                        }
                    }
                }
            }
        }
        return new ProxyProperty(arr);
    }
    
    /** Property delegating to an array of Properties. It either
     * delegates to original[0] or applies changes to all
     * original properties.
     */
    private static class ProxyProperty extends Node.Property {
        
        private Node.Property[] original;
       
        /** It sets name, displayName and short description.
         * Remembers original.
         */
        public ProxyProperty(Node.Property[] original) {
            super(original[0].getValueType());
            this.original = original;
            setName(original[0].getName());
            setDisplayName(original[0].getDisplayName());
            setShortDescription(original[0].getShortDescription());
        }
        
        /** Test whether the property is writable.Calls all delegates.
         * If any of them returns false returns false, otherwise return true.
         */
        public boolean canWrite() {
            for (int i = 0; i < original.length; i++) {
                if (!original[i].canWrite()) {
                    return false;
                }
            }
            return true;
        }
        
        /** Test whether the property is readable. Calls all delegates.
         * If any of them returns false returns false, otherwise return true.
         * @return true if all delegates returned true
         */
        public boolean canRead() {
            for (int i = 0; i < original.length; i++) {
                if (!original[i].canRead()) {
                    return false;
                }
            }
            return true;
        }
        
        /** If all values are the same returns the value otherwise returns null.
         * @return the value of the property
         * @exception IllegalAccessException cannot access the called method
         * @exception InvocationTargetException an exception during invocation
         */
        public Object getValue() throws IllegalAccessException, java.lang.reflect.InvocationTargetException {
            Object o = original[0].getValue();
            if (o == null) {
                return null;
            }
            for (int i = 0; i < original.length; i++) {
                if (! o.equals(original[i].getValue())) {
                    throw new DifferentValuesException();
                }
            }
            return o;
        }
        
        /** Set the value. Calls setValue on all delegates.
         * @param val the new value of the property
         * @exception IllegalAccessException cannot access the called method
         * @exception IllegalArgumentException wrong argument
         * @exception InvocationTargetException an exception during invocation
         */
        public void setValue(Object val) throws IllegalAccessException, IllegalArgumentException, java.lang.reflect.InvocationTargetException {
            for (int i = 0; i < original.length; i++) {
                original[i].setValue(val);
            }
        }
        
        /** Retrieve a named attribute with this feature.
         * If all values are the same returns the value otherwise returns null.
         * @param attributeName  The locale-independent name of the attribute
         * @return The value of the attribute.  May be null if
         *      the attribute is unknown.
         */
        public Object getValue (String attributeName) {
            Object o = original[0].getValue (attributeName);
            if (Boolean.FALSE.equals(o)) {
                //issue 38319 - Boolean.FALSE should override even null -
                //relevant primarily to the general hint canEditAsText,
                //but makes sense generally
                return o;
            }
            if (o == null) {
                return null;
            }
            for (int i = 1; i < original.length; i++) {
                if (Boolean.FALSE.equals(original[i])) {
                    //issue 38319, see comment above
                    return original[i];
                }
                if (! o.equals (original[i].getValue (attributeName))) {
                    //Optionally log it and return null
                    if (Boolean.getBoolean("netbeans.ps.logDifferentValues")) { //NOI18N
                        ErrorManager.getDefault ().notify (
                            ErrorManager.INFORMATIONAL,
                            new DifferentValuesException (
                            "Different values in attribute " + attributeName + 
                            " for proxy property " + getDisplayName() + "(" + 
                            this + ") first value=" + o + " property " + i + "("
                            + original[i].getClass().getName() + " returns " +
                            original[i].getValue(attributeName))); // NOI18N
                    }
                    return null;
                }
            }
            return o;
        }
        
        /** Associate a named attribute with this feature. Calls setValue on all delegates.
         * @param attributeName  The locale-independent name of the attribute
         * @param value  The value.
         */
        public void setValue (String attributeName, Object value) {
            for (int i = 0; i < original.length; i++) {
                original[i].setValue (attributeName, value);
            }
        }
        
        /**
         * @returns property editor from the first delegate
         */
        public java.beans.PropertyEditor getPropertyEditor () {
            return original[0].getPropertyEditor();
        }
        
        /** Test whether the property has a default value. If any of
         * the delegates does not support default value returns false,
         * otherwise returns true.
         * @return true if all delegates returned true
         */
        public boolean supportsDefaultValue () {
            for (int i = 0; i < original.length; i++) {
                if (!original[i].supportsDefaultValue()) {
                    return false;
                }
            }
            return true;
        }

        /** 
         * Calls restoreDefaultValue on all delegates (original).
         * @exception IllegalAccessException cannot access the called method
         * @exception InvocationTargetException an exception during invocation
         */
        public void restoreDefaultValue() throws IllegalAccessException, java.lang.reflect.InvocationTargetException {
            for (int i = 0; i < original.length; i++) {
                original[i].restoreDefaultValue();
            }
        }
        
        public String toString() {
            StringBuffer sb = new StringBuffer("Proxy property for: ");
            sb.append(getDisplayName());
            sb.append('[');
            for (int i=0; i < original.length; i++) {
                sb.append (original[i].getClass().getName());
                if (i < original.length-1) {
                    sb.append(',');
                }
            }
            sb.append(']');
            return sb.toString();
        }
    }
    
    /** We cannot return a single value when there are different values */
    static class DifferentValuesException extends RuntimeException {
        public DifferentValuesException () {
            super ();
        }
        public DifferentValuesException (String message) {
            super (message);
        }
    }
}
... 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.