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.netbeans.modules.form.layoutsupport.delegates;

import java.awt.*;
import java.beans.*;
import java.util.*;
import java.lang.reflect.Constructor;

import org.openide.nodes.Node;
import org.openide.util.Utilities;
import org.openide.util.SharedClassObject;

import org.netbeans.lib.awtextra.AbsoluteLayout;
import org.netbeans.lib.awtextra.AbsoluteConstraints;

import org.netbeans.modules.form.layoutsupport.*;
import org.netbeans.modules.form.codestructure.*;
import org.netbeans.modules.form.FormProperty;
import org.netbeans.modules.form.FormLoaderSettings;

/**
 * Support class for AbsoluteLayout - for absolute positioning and sizing of
 * components using AbsoluteConstraints. This is an example of support for
 * layout manager using component constraints as complex objects initialized
 * by constructor with parameters mapped to properties. AbsoluteLayoutSupport
 * is also the superclass of NullLayoutSupport and JLayeredPane support, so it
 * is a bit more complicated than would be necessary for simple implementation.
 *
 * @author Tomas Pavek
 */

public class AbsoluteLayoutSupport extends AbstractLayoutSupport {

    /** The icon for AbsoluteLayout. */
    private static String iconURL =
        "org/netbeans/modules/form/layoutsupport/resources/AbsoluteLayout.gif"; // NOI18N
    /** The icon for AbsoluteLayout. */
    private static String icon32URL =
        "org/netbeans/modules/form/layoutsupport/resources/AbsoluteLayout32.gif"; // NOI18N

    private static Constructor constrConstructor;

    private static FormLoaderSettings formSettings = (FormLoaderSettings)
                   SharedClassObject.findObject(FormLoaderSettings.class, true);

    /** Gets the supported layout manager class - AbsoluteLayout.
     * @return the class supported by this delegate
     */
    public Class getSupportedClass() {
        return AbsoluteLayout.class;
    }

    /** Provides an icon to be used for the layout node in Component
     * Inspector. Only 16x16 color icon is required.
     * @param type is one of BeanInfo constants: ICON_COLOR_16x16,
     *        ICON_COLOR_32x32, ICON_MONO_16x16, ICON_MONO_32x32
     * @return icon to be displayed for node in Component Inspector
     */
    public Image getIcon(int type) {
        switch (type) {
            case BeanInfo.ICON_COLOR_16x16:
            case BeanInfo.ICON_MONO_16x16:
                return Utilities.loadImage(iconURL);
            default:
                return Utilities.loadImage(icon32URL);
        }
    }

    /** This method is called when switching layout - giving an opportunity to
     * convert the previous constrainst of components to constraints of the new
     * layout (this layout). For AbsoluteLayout, we can simply create new
     * constraints from positions and sizes of real components.
     * @param previousConstraints [input] layout constraints of components in
     *                                    the previous layout
     * @param currentConstraints [output] array of converted constraints for
     *                                    the new layout - to be filled
     * @param components [input] real components in a real container having the
     *                           previous layout
     */
    public void convertConstraints(LayoutConstraints[] previousConstraints,
                                   LayoutConstraints[] currentConstraints,
                                   Component[] components)
    {
        if (currentConstraints == null || components == null)
            return;

        for (int i=0; i < currentConstraints.length; i++)
            if (currentConstraints[i] == null) {
                Rectangle bounds = components[i].getBounds();
                Dimension prefSize = components[i].getPreferredSize();
                int x = bounds.x;
                int y = bounds.y;
                int w = computeConstraintSize(bounds.width, -1, prefSize.width);
                int h = computeConstraintSize(bounds.height, -1, prefSize.height);

                currentConstraints[i] = new AbsoluteLayoutConstraints(x, y, w, h);
            }
    }

    /** This method calculates layout constraints for a component dragged
     * over a container (or just for mouse cursor being moved over container,
     * without any component).
     * @param container instance of a real container over/in which the
     *        component is dragged
     * @param containerDelegate effective container delegate of the container
     *        (for layout managers we always use container delegate instead of
     *        the container)
     * @param component the real component being dragged, can be null
     * @param index position (index) of the component in its container;
     *        -1 if there's no dragged component
     * @param posInCont position of mouse in the container delegate
     * @param posInComp position of mouse in the dragged component; null if
     *        there's no dragged component
     * @return new LayoutConstraints object corresponding to the position of
     *         the component in the container
     */
    public LayoutConstraints getNewConstraints(Container container,
                                               Container containerDelegate,
                                               Component component,
                                               int index,
                                               Point posInCont,
                                               Point posInComp)
    {
        int x = posInCont.x;
        int y = posInCont.y;
        int w = -1;
        int h = -1;

        LayoutConstraints constr = getConstraints(index);

        if (component != null) {
            int currentW;
            int currentH;

            if (constr instanceof AbsoluteLayoutConstraints) {
                currentW = ((AbsoluteLayoutConstraints)constr).w;
                currentH = ((AbsoluteLayoutConstraints)constr).h;
            }
            else {
                currentW = -1;
                currentH = -1;
            }

            Dimension size = component.getSize();
            Dimension prefSize = component.getPreferredSize();

            w = computeConstraintSize(size.width, currentW, prefSize.width);
            h = computeConstraintSize(size.height, currentH, prefSize.height);
        }

        if (posInComp != null) {
            x -= posInComp.x;
            y -= posInComp.y;
        }

        if (formSettings.getApplyGridToPosition()) {
            x = computeGridSize(x, formSettings.getGridX());
            y = computeGridSize(y, formSettings.getGridY());
        }

        return createNewConstraints(constr, x, y, w, h);
    }

    /** This method paints a dragging feedback for a component dragged over
     * a container (or just for mouse cursor being moved over container,
     * without any component). For AbsoluteLayout, it simply paints a rectangle
     * corresponding to the component position and size.
     * @param container instance of a real container over/in which the
     *        component is dragged
     * @param containerDelegate effective container delegate of the container
     *        (for layout managers we always use container delegate instead of
     *        the container)
     * @param component the real component being dragged, can be null
     * @param newConstraints component layout constraints to be presented
     * @param newIndex component's index position to be presented; not used
     *        for AbsoluteLayout
     * @param g Graphics object for painting (with color and line style set)
     * @return whether any feedback was painted (true in this case)
     */
    public boolean paintDragFeedback(Container container, 
                                     Container containerDelegate,
                                     Component component,
                                     LayoutConstraints newConstraints,
                                     int newIndex,
                                     Graphics g)
    {
        Rectangle r = ((AbsoluteLayoutConstraints)newConstraints).getBounds();
        int w = r.width;
        int h = r.height;

        if (w == -1 || h == -1) {
            // JInternalFrame.getPreferredSize() behaves suspiciously
            Dimension pref = component instanceof javax.swing.JInternalFrame ?
                             component.getSize() : component.getPreferredSize();
            if (w == -1) w = pref.width;
            if (h == -1) h = pref.height;
        }

        if (w < 4) w = 4;
        if (h < 4) h = 4;

        g.drawRect(r.x, r.y, w, h);

        return true;
    }

    /** Provides resizing options for given component. It can combine the
     * bit-flag constants RESIZE_UP, RESIZE_DOWN, RESIZE_LEFT, RESIZE_RIGHT.
     * @param container instance of a real container in which the
     *        component is to be resized
     * @param containerDelegate effective container delegate of the container
     *        (e.g. like content pane of JFrame)
     * @param component real component to be resized
     * @param index position of the component in its container
     * @return resizing options for the component; 0 if no resizing is possible
     */
    public int getResizableDirections(Container container,
                                      Container containerDelegate,
                                      Component component,
                                      int index)
    {
        return RESIZE_UP | RESIZE_DOWN | RESIZE_LEFT | RESIZE_RIGHT;
    }

    /** This method should calculate layout constraints for a component being
     * resized.
     * @param container instance of a real container in which the
     *        component is resized
     * @param containerDelegate effective container delegate of the container
     *        (e.g. like content pane of JFrame)
     * @param component real component being resized
     * @param index position of the component in its container
     * @param sizeChanges Insets object with size differences
     * @param posInCont position of mouse in the container delegate
     * @return component layout constraints for resized component; null if
     *         resizing is not possible or not implemented
     */
    public LayoutConstraints getResizedConstraints(Container container,
                                                   Container containerDelegate,
                                                   Component component,
                                                   int index,
                                                   Insets sizeChanges,
                                                   Point posInCont)
    {
        int x, y, w, h;
        Rectangle bounds = component.getBounds();
        x = bounds.x;
        y = bounds.y;
        w = bounds.width;
        h = bounds.height;

        Dimension prefSize = component.getPreferredSize();
        int currentW, currentH;

        LayoutConstraints constr = getConstraints(index);
        if (constr instanceof AbsoluteLayoutConstraints) {
            Rectangle r = ((AbsoluteLayoutConstraints)constr).getBounds();
            currentW = r.width;
            currentH = r.height;
        }
        else {
            currentW = computeConstraintSize(w, -1, prefSize.width);
            currentH = computeConstraintSize(h, -1, prefSize.height);
        }

        int x2 = x + w;
        int y2 = y + h;

        if (sizeChanges.left + sizeChanges.right == 0)
            w = currentW; // no change
        else { // compute resized width and x coordinate
            w += sizeChanges.left + sizeChanges.right;
            w = w <= 0 ? -1 : computeConstraintSize(w, currentW, prefSize.width);

            if (w > 0) {
                if (formSettings.getApplyGridToSize()) {
                    int gridW = computeGridSize(w, formSettings.getGridX());
                    x -= sizeChanges.left +
                         (gridW - w) * sizeChanges.left
                         / (sizeChanges.left + sizeChanges.right);
                    w = gridW;
                }
            }
            else if (sizeChanges.left != 0)
                x = x2 - prefSize.width;
        }

        if (sizeChanges.top + sizeChanges.bottom == 0)
            h = currentH; // no change
        else { // compute resized height and y coordinate
            h += sizeChanges.top + sizeChanges.bottom;
            h = h <= 0 ? -1 : computeConstraintSize(h, currentH, prefSize.height);

            if (h > 0) {
                if (formSettings.getApplyGridToSize()) {
                    int gridH = computeGridSize(h, formSettings.getGridY());
                    y -= sizeChanges.top +
                         (gridH - h) * sizeChanges.top
                         / (sizeChanges.top + sizeChanges.bottom);
                    h = gridH;
                }
            }
            else if (sizeChanges.top != 0)
                y = y2 - prefSize.height;
        }

        return createNewConstraints(constr, x, y, w, h);
    }

    // -------

    /** This method is called from readComponentCode method to read layout
     * constraints of a component from code (AbsoluteConstraints in this case).
     * @param constrExp CodeExpression object of the constraints (taken from
     *        add method in the code)
     * @param constrCode CodeGroup to be filled with the relevant constraints
     *        initialization code; not needed here because AbsoluteConstraints
     *        object is represented only by a single code expression (based on
     *        constructor) and no statements
     * @param compExp CodeExpression of the component for which the constraints
     *        are read (not needed here)
     * @return LayoutConstraints based on information read form code
     */
    protected LayoutConstraints readConstraintsCode(CodeExpression constrExp,
                                                    CodeGroup constrCode,
                                                    CodeExpression compExp)
    {
        AbsoluteLayoutConstraints constr =
            new AbsoluteLayoutConstraints(0, 0, -1, -1);

        CodeExpression[] params = constrExp.getOrigin().getCreationParameters();
        if (params.length == 4) {
            // reading is done in AbsoluteLayoutConstraints
            constr.readPropertyExpressions(params, 0);
        }

        return constr;
    }

    /** Called from createComponentCode method, creates code for a component
     * layout constraints (opposite to readConstraintsCode).
     * @param constrCode CodeGroup to be filled with constraints code; not
     *        needed here because AbsoluteConstraints object is represented
     *        only by a single constructor code expression and no statements
     * @param constr layout constraints metaobject representing the constraints
     * @param compExp CodeExpression object representing the component; not
     *        needed here
     * @return created CodeExpression representing the layout constraints
     */
    protected CodeExpression createConstraintsCode(CodeGroup constrCode,
                                                   LayoutConstraints constr,
                                                   CodeExpression compExp,
                                                   int index)
    {
        if (!(constr instanceof AbsoluteLayoutConstraints))
            return null;

        AbsoluteLayoutConstraints absConstr = (AbsoluteLayoutConstraints)constr;
        // code expressions for constructor parameters are created in
        // AbsoluteLayoutConstraints
        CodeExpression[] params = absConstr.createPropertyExpressions(
                                                 getCodeStructure(), 0);
        return getCodeStructure().createExpression(getConstraintsConstructor(),
                                                   params);
    }

    /** This method is called to get a default component layout constraints
     * metaobject in case it is not provided (e.g. in addComponents method).
     * @return the default LayoutConstraints object for the supported layout
     */
    protected LayoutConstraints createDefaultConstraints() {
        return new AbsoluteLayoutConstraints(0, 0, -1, -1);
    }

    // --------

    protected LayoutConstraints createNewConstraints(
                                    LayoutConstraints currentConstr,
                                    int x, int y, int w, int h)
    {
        return new AbsoluteLayoutConstraints(x, y, w, h);
    }

    private static int computeConstraintSize(int newSize,
                                             int currSize,
                                             int prefSize) {
        return newSize != -1 && (newSize != prefSize
                                 || (currSize != -1 && currSize == prefSize)) ?
               newSize : -1;
    }

    private static int computeGridSize(int size, int step) {
        if (step <= 0) return size;
        int mod = size % step;
        return mod >= step/2 ? size + step - mod : size - mod;
    }

    private static Constructor getConstraintsConstructor() {
        if (constrConstructor == null) {
            try {
                constrConstructor = AbsoluteConstraints.class.getConstructor(
                                    new Class[] { Integer.TYPE, Integer.TYPE,
                                                  Integer.TYPE, Integer.TYPE });
            }
            catch (NoSuchMethodException ex) { // should not happen
                ex.printStackTrace();
            }
        }
        return constrConstructor;
    }

    // -------------

    /** LayoutConstraints implementation class for AbsoluteConstraints.
     */
    public static class AbsoluteLayoutConstraints implements LayoutConstraints {
        int x, y, w, h; // position and size

        private Node.Property[] properties;
        boolean nullMode;
        Component refComponent;

        public AbsoluteLayoutConstraints(int x, int y, int w, int h)
        {
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
        }

        public Node.Property[] getProperties() {
            if (properties == null) {
                properties = createProperties();
                reinstateProperties();
            }
            return properties;
        }

        public Object getConstraintsObject() {
            return new AbsoluteConstraints(x, y, w, h);
        }

        public LayoutConstraints cloneConstraints() {
            return new AbsoluteLayoutConstraints(x, y, w, h);
        }

        // --------

        public Rectangle getBounds() {
            return new Rectangle(x, y, w, h);
        }

        protected Node.Property[] createProperties() {
            return new Node.Property[] {
                new FormProperty("AbsoluteLayoutConstraints posx", // NOI18N
                                 Integer.TYPE,
                             getBundle().getString("PROP_posx"), // NOI18N
                             getBundle().getString("HINT_posx")) { // NOI18N

                    public Object getTargetValue() {
                        return new Integer(x);
                    }
                    public void setTargetValue(Object value) {
                        x = ((Integer)value).intValue();
                    }
                    public void setPropertyContext(
                        org.netbeans.modules.form.FormPropertyContext ctx)
                    { // disabling this method due to limited persistence
                    } // capabilities (compatibility with previous versions)
                },

                new FormProperty("AbsoluteLayoutConstraints posy", // NOI18N
                                 Integer.TYPE,
                             getBundle().getString("PROP_posy"), // NOI18N
                             getBundle().getString("HINT_posy")) { // NOI18N

                    public Object getTargetValue() {
                        return new Integer(y);
                    }
                    public void setTargetValue(Object value) {
                        y = ((Integer)value).intValue();
                    }
                    public void setPropertyContext(
                        org.netbeans.modules.form.FormPropertyContext ctx)
                    { // disabling this method due to limited persistence
                    } // capabilities (compatibility with previous versions)
                },

                new FormProperty("AbsoluteLayoutConstraints width", // NOI18N
                                 Integer.TYPE,
                             getBundle().getString("PROP_width"), // NOI18N
                             getBundle().getString("HINT_width")) { // NOI18N

                    public Object getTargetValue() {
                        return new Integer(w);
                    }
                    public void setTargetValue(Object value) {
                        w = ((Integer)value).intValue();
                    }
                    public boolean supportsDefaultValue () {
                        return true;
                    }
                    public Object getDefaultValue() {
                        return new Integer(-1);
                    }
                    public PropertyEditor getExpliciteEditor() {
                        return new SizeEditor();
                    }
                    public Object getValue(String key) {
                        if ("canEditAsText".equals(key)) // NOI18N
                            return Boolean.TRUE;
                        return super.getValue(key);
                    }
                    public String getJavaInitializationString() {
                        if (nullMode && refComponent != null && !isChanged())
                            return Integer.toString(
                                     refComponent.getPreferredSize().width);
                        return super.getJavaInitializationString();
                    }
                    public void setPropertyContext(
                        org.netbeans.modules.form.FormPropertyContext ctx)
                    { // disabling this method due to limited persistence
                    } // capabilities (compatibility with previous versions)
                },

                new FormProperty("AbsoluteLayoutConstraints height", // NOI18N
                                 Integer.TYPE,
                             getBundle().getString("PROP_height"), // NOI18N
                             getBundle().getString("HINT_height")) { // NOI18N

                    public Object getTargetValue() {
                        return new Integer(h);
                    }
                    public void setTargetValue(Object value) {
                        h = ((Integer)value).intValue();
                    }
                    public boolean supportsDefaultValue () {
                        return true;
                    }
                    public Object getDefaultValue() {
                        return new Integer(-1);
                    }
                    public PropertyEditor getExpliciteEditor() {
                        return new SizeEditor();
                    }
                    public Object getValue(String key) {
                        if ("canEditAsText".equals(key)) // NOI18N
                            return Boolean.TRUE;
                        return super.getValue(key);
                    }
                    public String getJavaInitializationString() {
                        if (nullMode && refComponent != null && !isChanged())
                            return Integer.toString(
                                     refComponent.getPreferredSize().height);
                        return super.getJavaInitializationString();
                    }
                    public void setPropertyContext(
                        org.netbeans.modules.form.FormPropertyContext ctx)
                    { // disabling this method due to limited persistence
                    } // capabilities (compatibility with previous versions)
                }
            };
        }

        private void reinstateProperties() {
            try {
                for (int i=0; i < properties.length; i++) {
                    FormProperty prop = (FormProperty) properties[i];
                    prop.reinstateProperty();
                }
            }
            catch(IllegalAccessException e1) {} // should not happen
            catch(java.lang.reflect.InvocationTargetException e2) {} // should not happen
        }

        /** This method creates CodeExpression objects for properties of
         * AbsoluteConstraints - this is used by the layout delegate's method
         * createConstraintsCode which uses the expressions as parameters
         * in AbsoluteConstraints constructor.
         * @param codeStructure main CodeStructure object in which the code
         *        expressions are created
         * @param shift this parameter is used only by subclasses of
         *        AbsoluteLayoutConstraints (which may insert another
         *        constructor parameters before x, y, w and h)
         * @return array of created code expressions
         */
        protected final CodeExpression[] createPropertyExpressions(
                                             CodeStructure codeStructure,
                                             int shift)
        {
            // first make sure properties are created...
            getProperties();

            // ...then create code expressions based on the properties
            CodeExpression xEl = codeStructure.createExpression(
                           FormCodeSupport.createOrigin(properties[shift++]));
            CodeExpression yEl = codeStructure.createExpression(
                           FormCodeSupport.createOrigin(properties[shift++]));
            CodeExpression wEl = codeStructure.createExpression(
                           FormCodeSupport.createOrigin(properties[shift++]));
            CodeExpression hEl = codeStructure.createExpression(
                           FormCodeSupport.createOrigin(properties[shift++]));
            return new CodeExpression[] { xEl, yEl, wEl, hEl };
        }

        /** This method reads CodeExpression objects for properties (used as
         * AbsoluteConstraints constructor parameters). Called by layout
         * delegate's readConstraintsCode method.
         * @param exps array of code expressions to read to properties
         * @param shift this parameter is used only by subclasses of
         *        AbsoluteLayoutConstraints (which may insert another
         *        constructor parameters before x, y, w and h)
         */
        protected final void readPropertyExpressions(CodeExpression[] exps,
                                                     int shift)
        {
            // first make sure properties are created...
            getProperties();

            // ...then map the properties to the code expressions
            for (int i=0; i < exps.length; i++)
                FormCodeSupport.readPropertyExpression(exps[i],
                                                       properties[i+shift],
                                                       false);
        }
    }

    // -----------

    /** PropertyEditor for width and height properties of
     * AbsoluteLayoutConstraints.
     */
    public static final class SizeEditor extends PropertyEditorSupport {

        final Integer prefValue = new Integer(-1);
        final String prefTag = getBundle().getString("VALUE_preferred"); // NOI18N

        public String[] getTags() {
            return new String[] { prefTag };
        }

        public String getAsText() {
            Object value = getValue();
            return prefValue.equals(value) ?
                     prefTag : value.toString();
        }

        public void setAsText(String str) {
            if (prefTag.equals(str))
                setValue(prefValue);
            else
                try {
                    setValue(new Integer(Integer.parseInt(str)));
                } 
                catch (NumberFormatException e) {} // ignore
        }

        public String getJavaInitializationString() {
            Object value = getValue();
            return value != null ? value.toString() : null;
        }
    }
}
... 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.