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.
 */
/*
 * EditorPropertyDisplayer_java
 *
 * Created on 18 October 2003, 16:36
 */

package org.openide.explorer.propertysheet;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.beans.FeatureDescriptor;
import java.beans.PropertyEditor;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import javax.swing.*;
import org.openide.nodes.Node.Property;
import org.openide.util.Utilities;

/** An implementation of PropertyDisplayer_Inline which replicates the inline
 * editor mode of PropertyPanel.  This class is a base class which is simply
 * responsible for finding and embedding the correct inline editor - it contains
 * no code for actually updating the value or anything such.  That code is in
 * EditablePropertyDisplayer, to improve readability and maintainability.
 *
 * @author  Tim Boudreau
 */
class EditorPropertyDisplayer extends JComponent implements PropertyDisplayer_Inline {
    private Property prop=null;
    private InplaceEditor inplace=null;
    private JComponent inner=null;
    private int radioButtonMax=0;
    private boolean showCustomEditorButton=true;
    private boolean tableUI=false;
    private boolean useLabels=true;
    private PropertyEnv env=null;
    private boolean radioBoolean = false;
    protected WeakReference modelRef=null;
    
    /** Creates a new instance of EditorPropertyDisplayer */
    public EditorPropertyDisplayer(Property p) {
        this(p,null);
    }
    
    EditorPropertyDisplayer(Property p, PropertyModel mdl) {
        if (p == null) {
            throw new NullPointerException("Property may not be null"); //NOI18N
        }
        this.prop = p;
        if (mdl != null) {
            modelRef = new WeakReference(mdl);
        }
    }
    
    
    
    public void addNotify() {
        try {
            if (inner == null) {
                replaceInner();
            }
        } finally {
            super.addNotify();
        }
    }
    
    protected void processFocusEvent(FocusEvent fe) {
        super.processFocusEvent(fe);
        if (fe.getID() == FocusEvent.FOCUS_GAINED && inner != null) {
            inner.requestFocus();
        }
    }
    
    public void removeNotify() {
        super.removeNotify();
        setInplaceEditor(null);
        reusableEnv.clear();
    }
    
    public final Component getComponent() {
        return this;
    }
    
    public final Property getProperty() {
        return prop;
    }
    
    public final int getRadioButtonMax() {
        return radioButtonMax;
    }
    
    public final boolean isShowCustomEditorButton() {
        boolean result = showCustomEditorButton;
        if (getProperty() != null) {
            Boolean explicit = (Boolean) getProperty().getValue(
                "suppressCustomEditor"); //NOI18N
            
            if (explicit != null) {
                result = !explicit.booleanValue();
            }
        }
        return result;
    }
    
    public final boolean isTableUI() {
        return tableUI;
    }
    
    public final void refresh() {
        if (isDisplayable()) {
            replaceInner();
        }
    }
    
    public final boolean isUseLabels() {
        return useLabels;
    }
    
    public final void setRadioButtonMax(int max) {
        if (max != radioButtonMax) {
            int old = radioButtonMax;
            boolean needChange=false;
            if (inplace != null) {
                InplaceEditor innermost = 
                    PropUtils.findInnermostInplaceEditor(inplace);
                
                if (innermost instanceof JComboBox || innermost instanceof RadioInplaceEditor) {
                    PropertyEditor ped = innermost.getPropertyEditor();
                    int tagCount = ped.getTags() == null ? -1 : ped.getTags().length;
                    needChange = old <= tagCount != max <= tagCount;
                }
            }
            
            radioButtonMax = max;
            
            if (needChange && inner != null) {
                replaceInner();
                firePropertyChange("preferredSize", null, null); //NOI18N
            }
        }
    }
    
    public final void setShowCustomEditorButton(boolean val) {
        //If the property descriptor explicitly says it does not
        //want a custom editor button, this overrides anything set on
        //the PropertyPanel.
        if (getProperty() != null) {
            Property p = getProperty();
            Boolean explicit = (Boolean) p.getValue("suppressCustomEditor"); //NOI18N
            if (explicit != null) {
                val = explicit.booleanValue();
                System.err.println("Found explicit value: " + val);
            }
        }
        if (showCustomEditorButton != val) {
            showCustomEditorButton=val;
            replaceInner();
        }
    }
    
    public final void setTableUI(boolean val) {
        if (val != tableUI) {
            tableUI = val;
            replaceInner();
        }
    }
    
    public final void setUseLabels(boolean useLabels) {
        if (useLabels != this.useLabels) {
            
            boolean needChange = false;
            if (isShowing()) {
                InplaceEditor innermost = 
                    PropUtils.findInnermostInplaceEditor(
                    inplace);
                
                needChange = (innermost instanceof RadioInplaceEditor || 
                    innermost instanceof JCheckBox);
            }
            
            this.useLabels = useLabels;
            
            if (needChange && inner != null) {
                replaceInner();
            }
        }
    }
    
    public final void requestFocus() {
        if (inner != null) {
            inner.requestFocus();
        } else {
            super.requestFocus();
        }
    }
    
    public final Dimension getPreferredSize() {
        Dimension result;
        if (inner == null) {
            //Use the renderer infrastructure to do it if we're not initialized
            result = new RendererPropertyDisplayer(getProperty()).getRenderer(this).getPreferredSize();
        } else {
            result = inner.getPreferredSize();
        }
        return result;
    }
    
    public final boolean requestFocusInWindow() {
        boolean result;
        if (inner != null) {
            result = inner.requestFocusInWindow();
        } else {
            result = super.requestFocusInWindow();
        }
        return result;
    }
    
    private final void installInner (JComponent c) {
        synchronized (getTreeLock()) {
            if (inner != null) {
                if (c != null) {
//                    System.err.println("REPLACING INNER COMPONENT");
                }
                remove(inner);
            }
            inner = c;
            if (inner != null) {
                c.setBounds(0,0,getWidth(),getHeight());
                add(c);
            }
        }
    }
    
    protected boolean inReplaceInner=false;
    protected final void replaceInner() {
        inReplaceInner = true;
        try {
            Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
            boolean hadFocus = isEnabled() && 
                (focusOwner == this || isAncestorOf(focusOwner) || 
                  (getInplaceEditor() != null && 
                  getInplaceEditor().isKnownComponent(focusOwner)));
            
            //Figure out if a combo popup was open, so we can re-open it.
            //If we're processing a mouse event, close it because that's
            //the normal behavior of a popup.  We want arrow keyboard events
            //to not trigger closing of the popup if they caused a change
            //to a value that is marked as invalid
            boolean wasComboPopup = hadFocus && focusOwner instanceof JComboBox && ((JComboBox) focusOwner).isPopupVisible() &&
                (EventQueue.getCurrentEvent() instanceof KeyEvent && (((KeyEvent) EventQueue.getCurrentEvent()).getKeyCode() ==
                KeyEvent.VK_UP || ((KeyEvent) EventQueue.getCurrentEvent()).getKeyCode() == KeyEvent.VK_DOWN));

//            System.err.println("REPLACE INNER - " + prop.getDisplayName() + " focus:" + hadFocus);
            
            if (hadFocus) {
                //We don't want focus to jump to another component and back
                KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
            }

            setInplaceEditor(createInplaceEditor());
            
            if (hadFocus) {
                requestFocus();
                //At this point the focus owner is still null, the event is queued - 
                if (wasComboPopup) {
                    //We have to let the request focus on the event queue get
                    //processed before this can be done, or the component will
                    //not yet be laid out and the popup will be 1 pixel wide
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            InplaceEditor ied = getInplaceEditor();
                            ied = PropUtils.findInnermostInplaceEditor(ied);
                            JComponent c = ied.getComponent();
                            if (c instanceof JComboBox && c.isShowing()) {
                                ((JComboBox) c).showPopup();
                            }
                        }
                    });
                }
            } 
            revalidate();
            repaint();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            inReplaceInner = false;
        }
    }
    
    protected final JComponent getInner() {
        return inner;
    }
    
    protected void setInplaceEditor(InplaceEditor ed) {
        if (inplace != ed) {
            if (inplace != null) {
                inplace.clear();
            }
            inplace = ed;
            if (ed == null) {
                installInner(null);
            } else {
                JComponent comp = inplace.getComponent();
                prepareComponent(inplace);
                installInner(comp);
            }
        }
    }
    
    public void setEnabled(boolean b) {
        if (inner != null) {
            inner.setEnabled(b);
        }
        super.setEnabled(b);
    }
    
    public void setBackground(Color c) {
        super.setBackground(c);
        if (inner != null) {
            if (inplace != null && inplace.supportsTextEntry()) {
                inner.setBackground(PropUtils.getTextFieldBackground());
            } else {
                inner.setBackground(c);
            }
        }
    }
    
    public void setForeground(Color c) {
        super.setForeground(c);
        if (inner != null) {
            if (inplace != null && inplace.supportsTextEntry()) {
                inner.setForeground(PropUtils.getTextFieldForeground());
            } else {
                inner.setForeground(c);
            }
        }
    }
    
    protected void prepareComponent (InplaceEditor inplace) {
        InplaceEditor innermost = PropUtils.findInnermostInplaceEditor(inplace);
        JComponent comp = innermost.getComponent();
        if (!isTableUI() && inplace.supportsTextEntry()) {
            comp.setBackground(PropUtils.getTextFieldBackground());
            comp.setForeground(PropUtils.getTextFieldForeground());
        } else {
            comp.setBackground(getBackground());
            if (!isEnabled() || !prop.canWrite()) {
                comp.setForeground(UIManager.getColor("textInactiveText"));
            } else {
                comp.setForeground(getForeground());
            }
        }
        comp.setEnabled(isEnabled() && 
            PropUtils.checkEnabled(this, inplace.getPropertyEditor(), 
            getPropertyEnv()));
    }
    
    public void reshape(int x, int y, int w, int h) {
        if (inner != null) {
            inner.setBounds(0,0, w,h);
        }
        super.reshape(x,y,w,h);
    }
    
    protected void setPropertyEnv(PropertyEnv env) {
        this.env = env;
    }
    
    public final PropertyEnv getPropertyEnv() {
        return env;
    }
    
    protected final InplaceEditor getInplaceEditor() {
        return inplace;
    }
    
    protected void configureButtonPanel(ButtonPanel bp) {
    }

    /** Basically some hacks to acquire the underlying property descriptor in
     * the case of a wrapper.  This is here because some property editors will
     * cast the result of PropertyEnv.getFeatureDescriptor() as a specific 
     * implementation type, so even if we're wrapping a property model, we
     * still need to make sure we're returning the class they expect.  */
    static final FeatureDescriptor findFeatureDescriptor(PropertyDisplayer pd) {
        if (pd instanceof EditorPropertyDisplayer) {
            //Issue 38004, more gunk to ensure we get the right feature
            //descriptor
            EditorPropertyDisplayer epd = (EditorPropertyDisplayer) pd;
            if (epd.modelRef != null) {
                PropertyModel pm = (PropertyModel)epd.modelRef.get();
                if (pm instanceof ExPropertyModel) {
                    FeatureDescriptor fd = 
                        ((ExPropertyModel) pm).getFeatureDescriptor();
                    if (fd != null) {
                        return fd;
                    }
                }
            }
        }
        Property p = pd.getProperty();
        if (p instanceof ModelProperty) {
            return ((ModelProperty) p).getFeatureDescriptor();
        } else if (p instanceof ModelProperty.DPMWrapper) {
            return ((ModelProperty.DPMWrapper) p).getFeatureDescriptor();
        } else {
            return p;
        }
    }
    
    private InplaceEditor createInplaceEditor () {
        PropertyEnv env = new PropertyEnv();
        env.setFeatureDescriptor(findFeatureDescriptor(this));
        
        InplaceEditor result;
        //Get the real inplace editor
        InplaceEditor innermost = result = factory(this).getInplaceEditor(getProperty(), env, 
            true);
        
//        System.err.println("  CREATE INPLACE EDITOR - INNERMOST IS " + innermost);
        
        //See if it should be embedded in an instance of ButtonPanel to show
        //the custom editor button
        if (isShowCustomEditorButton() && 
            innermost.getPropertyEditor().supportsCustomEditor()) {
            
            ButtonPanel bp = new ButtonPanel();
            bp.setInplaceEditor(innermost);
//            System.err.println("  wrapping in a buttonpanel");
            configureButtonPanel(bp);
            result = bp;
        }
        Icon ic = null;
        
        //See if there's an icon to display, either invalid state or
        //a property-specified icon
        if (env.getState() == env.STATE_INVALID) {
            ic = new ImageIcon(Utilities.loadImage (
                        "org/openide/resources/propertysheet/invalid.gif")); //NOI18N
        } else if (getProperty().getValue("valueIcon") != null) { //NOI18N
            Object o = getProperty().getValue("valueIcon"); //NOI18N
            if (o instanceof Image) {
                ic = new ImageIcon((Image) o);
            } else {
                ic = (Icon) o;
            }
        }
        
        //If we have an icon, use an IconPanel to display it
        if (ic != null) {
            IconPanel iconPanel = new IconPanel();
            iconPanel.setIcon(ic);
            iconPanel.setInplaceEditor(result);
//            System.err.println("  wrapping in an IconPanel");
            result = iconPanel;
        }
        setPropertyEnv(env);
        return result;
    }
    
    private InplaceEditorFactory factory1=null;
    private InplaceEditorFactory factory2=null;
    private ReusablePropertyEnv reusableEnv = new ReusablePropertyEnv(); //XXX supply from PP?

    private InplaceEditorFactory factory(PropertyDisplayer_Inline inline) {
        InplaceEditorFactory result;
        if (inline.isTableUI()) {
            if (factory1 == null) {
                factory1 = new InplaceEditorFactory(inline.isTableUI(), inline.getReusablePropertyEnv());
            }
            result = factory1;
        } else {
            if (factory2 == null) {
                factory2 = new InplaceEditorFactory(inline.isTableUI(), inline.getReusablePropertyEnv());
            }
            result = factory2;
        }
        result.setUseRadioBoolean(inline.isRadioBoolean());
        result.setRadioButtonMax(inline.getRadioButtonMax());
        result.setUseLabels(inline.isUseLabels());
        return result;
    }
    
    public boolean isTitleDisplayed() {
        if (isUseLabels()) {
            InplaceEditor inp = null;
            if (inplace != null) {
                inp = inplace;
            } else {
                inp = createInplaceEditor();
            }
            InplaceEditor most = PropUtils.findInnermostInplaceEditor(inp);
            return (most instanceof RadioInplaceEditor || most instanceof CheckboxInplaceEditor);
        }
        return false;
    }
    
    public boolean isRadioBoolean() {
        return radioBoolean;
    }
    
    public void setRadioBoolean(boolean b) {
        radioBoolean = b;
    }

    public ReusablePropertyEnv getReusablePropertyEnv() {
        return reusableEnv;
    }

    static final Object[] findBeans(PropertyDisplayer pd) {
        Object[] result = null;
        if (pd instanceof EditorPropertyDisplayer) {
            //Issue 38132, fiendish evil to support PropertyEnv.getBeans()
            EditorPropertyDisplayer epd = (EditorPropertyDisplayer) pd;
            if (epd.modelRef != null) {
                PropertyModel pm = (PropertyModel)epd.modelRef.get();
                if (pm instanceof ExPropertyModel) {
                    result = ((ExPropertyModel) pm).getBeans();
                }
            }
        }
        if (result == null) {
            Property p = pd.getProperty();
            if (p instanceof ModelProperty) {
                result = ((ModelProperty) p).getBeans();
            } else if (p instanceof ModelProperty.DPMWrapper) {
                result = ((ModelProperty.DPMWrapper) p).getBeans();
             } else {
                if (pd instanceof EditorPropertyDisplayer && ((EditorPropertyDisplayer)pd).getParent() instanceof PropertyPanel) {
                    result = ((PropertyPanel) ((EditorPropertyDisplayer)pd).getParent()).getBeans();
                } else if (pd instanceof RendererPropertyDisplayer && ((RendererPropertyDisplayer) pd).getParent() instanceof PropertyPanel) {
                    result = ((PropertyPanel) ((RendererPropertyDisplayer)pd).getParent()).getBeans();
                }
            }
        }
        return result;
    }    
}
... 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.