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

import java.awt.*;
import java.beans.*;
import java.util.*;
import java.lang.reflect.Method;
import javax.swing.JSplitPane;

import org.openide.nodes.Node;

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

/**
 * Dedicated layout support class for JSplitPane.
 * @author Tomas Pavek
 */

public class JSplitPaneSupport extends AbstractLayoutSupport {

    private static Method setLeftComponentMethod;
    private static Method setRightComponentMethod;
    private static Method setTopComponentMethod;
    private static Method setBottomComponentMethod;

    /** Gets the supported layout manager class - JSplitPane.
     * @return the class supported by this delegate
     */
    public Class getSupportedClass() {
        return JSplitPane.class;
    }
    
    /** 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
     * @param component the real component being dragged, not needed here
     * @param index position (index) of the component in its container;
     *        not needed here
     * @param posInCont position of mouse in the container
     * @param posInComp position of mouse in the dragged component; not needed
     * @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)
    {
        if (!(container instanceof JSplitPane))
            return null;

        JSplitPane splitPane = (JSplitPane) container;
        Dimension sz = splitPane.getSize();
        int orientation = splitPane.getOrientation();
        Component left = splitPane.getLeftComponent();
        Component right = splitPane.getRightComponent();

        String freePosition = findFreePosition();
        
        if (left == null || right == null) {
            if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
                if (posInCont.x <= sz.width / 2)
                    freePosition = JSplitPane.LEFT;
                else
                    freePosition = JSplitPane.RIGHT;
            }
            else {
                if (posInCont.x <= sz.height / 2)
                    freePosition = JSplitPane.TOP;
                else
                    freePosition = JSplitPane.BOTTOM;
            }
        }

        return new SplitConstraints(freePosition);
    }

    /** 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).
     * @param container instance of a real container over/in which the
     *        component is dragged
     * @param containerDelegate effective container delegate of the container
     * @param component the real component being dragged; not needed here
     * @param newConstraints component layout constraints to be presented
     * @param newIndex component's index position to be presented; not needed
     * @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)
    {
        if (!(container instanceof JSplitPane))
            return false;

        String position = (String) newConstraints.getConstraintsObject();
        if (position == null)
            return false;
        
        JSplitPane splitPane = (JSplitPane) container;
        int orientation = splitPane.getOrientation();

        Dimension sz = splitPane.getSize();
        Insets insets = container.getInsets();
        sz.width -= insets.left + insets.right;
        sz.height -= insets.top + insets.bottom;

        Rectangle rect = new Rectangle(insets.left, insets.top, sz.width, sz.height);

        if (orientation == JSplitPane.HORIZONTAL_SPLIT) {
            Component left = splitPane.getLeftComponent();
            Component right = splitPane.getRightComponent();
            
            if (position == JSplitPane.LEFT) {
                if (right == null) {
                    rect.width = sz.width / 2;
                }
                else {
                    rect.width = right.getBounds().x - rect.x;
                }
            }
            else {
                if (left == null) {
                    rect.x = insets.left + sz.width / 2;
                    rect.width = sz.width - rect.x;
                }
                else {
                    rect.x = left.getBounds().x + left.getBounds().width;
                    rect.width = sz.width - rect.x;
                }
            }
        }
        else {
            Component top = splitPane.getTopComponent();
            Component bottom = splitPane.getBottomComponent();
            
            if (position == JSplitPane.TOP) {
                if (bottom == null) {
                    rect.height /= 2;
                }
                else {
                    rect.height = bottom.getBounds().y - rect.y;
                }
            }
            else {
                if (top == null) {
                    rect.y = insets.top + sz.height / 2;
                    rect.height = sz.height - rect.y;
                }
                else {
                    rect.y = top.getBounds().y + top.getBounds().height;
                    rect.height = sz.height - rect.y;
                }
            }
        }
        g.drawRect(rect.x, rect.y, rect.width, rect.height);
        return true;
    }

    /** Adds real components to given container (according to layout
     * constraints stored for the components).
     * @param container instance of a real container to be added to
     * @param containerDelegate effective container delegate of the container
     * @param components components to be added
     * @param index position at which to add the components to container
     */
    public void addComponentsToContainer(Container container,
                                         Container containerDelegate,
                                         Component[] components,
                                         int index)
    {
        if (!(container instanceof JSplitPane))
            return;

        for (int i=0; i < components.length; i++) {
            int descPos = convertPosition(getConstraints(i + index));
            if (descPos == 0)
                ((JSplitPane)container).setLeftComponent(components[i]);
            else if (descPos == 1)
                ((JSplitPane)container).setRightComponent(components[i]);
        }
    }

    /** Removes a real component from a real container.
     * @param container instance of a real container
     * @param containerDelegate effective container delegate of the container
     * @param component component to be removed
     * @return whether it was possible to remove the component (some containers
     *         may not support removing individual components reasonably)
     */
    public boolean removeComponentFromContainer(Container container,
                                                Container containerDelegate,
                                                Component component)
    {
        return false; // cannot remove component from JSplitPane
    }

    // ------

    /** This method is used for scanning code structures and recognizing
     * components added to containers and their constraints. It's called from
     * initialize method. When a relevant code statement is found, then the
     * CodeExpression of component is get and added to component, and also the
     * layout constraints information is read.
     * @param statement CodeStatement to be tested if it contains relevant code
     * @param componentCode CodeGroup to be filled with all component code
     * @return CodeExpression representing found component; null if the
     *         statement is not relevant
     */
    protected CodeExpression readComponentCode(CodeStatement statement,
                                               CodeGroup componentCode)
    {
        CodeExpression[] params = statement.getStatementParameters();
        if (params.length != 1)
            return null;

        String position;

        Object connectingObject = statement.getMetaObject();
        if (getSetLeftComponentMethod().equals(connectingObject))
            position = JSplitPane.LEFT;
        else if (getSetRightComponentMethod().equals(connectingObject))
            position = JSplitPane.RIGHT;
        else if (getSetTopComponentMethod().equals(connectingObject))
            position = JSplitPane.TOP;
        else if (getSetBottomComponentMethod().equals(connectingObject))
            position = JSplitPane.BOTTOM;
        else return null;

        SplitConstraints constr = new SplitConstraints(position);
        getConstraintsList().add(constr);

        componentCode.addStatement(statement);

        return params[0];
    }

    /** Creates code for a component added to the layout (opposite to
     * readComponentCode method).
     * @param componentCode CodeGroup to be filled with complete component code
     *        (code for initializing the layout constraints and adding the
     *        component to the layout)
     * @param componentExpression CodeExpression object representing component
     * @param index position of the component in the layout
     */
    protected void createComponentCode(CodeGroup componentCode,
                                       CodeExpression componentExpression,
                                       int index)
    {
        LayoutConstraints constr = getConstraints(index);
        if (!(constr instanceof SplitConstraints))
            return; // should not happen

        ((SplitConstraints)constr).createComponentCode(
                               componentCode,
                               getLayoutContext().getContainerCodeExpression(),
                               componentExpression);
    }

    /** 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;
     *         null if no component constraints are used
     */
    protected LayoutConstraints createDefaultConstraints() {
        return new SplitConstraints(findFreePosition());
    }

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

    private int convertPosition(LayoutConstraints desc) {
        Object position = desc.getConstraintsObject();
        if (JSplitPane.LEFT.equals(position) || JSplitPane.TOP.equals(position))
            return 0;
        if (JSplitPane.RIGHT.equals(position) || JSplitPane.BOTTOM.equals(position))
            return 1;
        return -1;
    }

    private String findFreePosition() {
        int leftTop = 0, rightBottom = 0;
        int orientation = JSplitPane.HORIZONTAL_SPLIT;

        for (int i=0, n=getComponentCount(); i < n; i++) {
            LayoutConstraints constraints = getConstraints(i);
            if (!(constraints instanceof SplitConstraints))
                continue;

            int constrPos = convertPosition(constraints);
            if (constrPos == 0)
                leftTop++;
            else if (constrPos == 1)
                rightBottom++;
        }

        if (leftTop == 0 || leftTop < rightBottom)
            return orientation == JSplitPane.HORIZONTAL_SPLIT ?
                JSplitPane.LEFT : JSplitPane.TOP;
        else
            return orientation == JSplitPane.HORIZONTAL_SPLIT ?
                JSplitPane.RIGHT : JSplitPane.BOTTOM;
    }

    // --------

    private static Method getSetLeftComponentMethod() {
        if (setLeftComponentMethod == null)
            setLeftComponentMethod = getAddMethod("setLeftComponent"); // NOI18N
        return setLeftComponentMethod;
    }

    private static Method getSetRightComponentMethod() {
        if (setRightComponentMethod == null)
            setRightComponentMethod = getAddMethod("setRightComponent"); // NOI18N
        return setRightComponentMethod;
    }

    private static Method getSetTopComponentMethod() {
        if (setTopComponentMethod == null)
            setTopComponentMethod = getAddMethod("setTopComponent"); // NOI18N
        return setTopComponentMethod;
    }

    private static Method getSetBottomComponentMethod() {
        if (setBottomComponentMethod == null)
            setBottomComponentMethod = getAddMethod("setBottomComponent"); // NOI18N
        return setBottomComponentMethod;
    }

    private static Method getAddMethod(String name) {
        try {
            return JSplitPane.class.getMethod(name,
                                              new Class[] { Component.class });
        }
        catch (NoSuchMethodException ex) { // should not happen
            ex.printStackTrace();
        }
        return null;
    }

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

    /** LayoutConstraints implementation holding component position in
     * JSplitPane.
     */
    public static class SplitConstraints implements LayoutConstraints {
        private String position;

        private Node.Property[] properties;

        private CodeExpression containerExpression;
        private CodeExpression componentExpression;
        private CodeGroup componentCode;

        public SplitConstraints(String position) {
            this.position = position;
        }

        public Node.Property[] getProperties() {
            if (properties == null)
                properties = new Node.Property[] {
                    new FormProperty(
                            "SplitConstraints splitPosition", // NOI18N
                            String.class,
                            getBundle().getString("PROP_splitPos"), // NOI18N
                            getBundle().getString("HINT_splitPos")) // NOI18N
                    {
                        public Object getTargetValue() {
                            return position;
                        }
                        public void setTargetValue(Object value) {
                            position = (String)value;
                        }
                        public PropertyEditor getExpliciteEditor() {
                            return new SplitPositionEditor();
                        }
                        protected void propertyValueChanged(Object old,
                                                            Object current) {
                            if (isChangeFiring())
                                updateCode();
                            super.propertyValueChanged(old, current);
                        }
                        public void setPropertyContext(
                            org.netbeans.modules.form.FormPropertyContext ctx)
                        { // disabling this method due to limited persistence
                        } // capabilities (compatibility with previous versions)
                    }
                };

            return properties;
        }

        public Object getConstraintsObject() {
            return position;
        }

        public LayoutConstraints cloneConstraints() {
            return new SplitConstraints(position);
        }

        private void createComponentCode(CodeGroup compCode,
                                         CodeExpression contExp,
                                         CodeExpression compExp)
        {
            componentCode = compCode;
            containerExpression = contExp;
            componentExpression = compExp;
            updateCode();
        }

        private void updateCode() {
            if (componentCode == null)
                return;

            CodeStructure.removeStatements(
                componentCode.getStatementsIterator());
            componentCode.removeAll();

            Method addMethod;
            if (JSplitPane.LEFT.equals(position))
                addMethod = getSetLeftComponentMethod();
            else if (JSplitPane.RIGHT.equals(position))
                addMethod = getSetRightComponentMethod();
            else if (JSplitPane.TOP.equals(position))
                addMethod = getSetTopComponentMethod();
            else if (JSplitPane.BOTTOM.equals(position))
                addMethod = getSetBottomComponentMethod();
            else return;

            componentCode.addStatement(
                    CodeStructure.createStatement(
                           containerExpression,
                           addMethod,
                           new CodeExpression[] { componentExpression }));
        }
    }

    static class SplitPositionEditor extends PropertyEditorSupport {
        private final String[] values = {
            JSplitPane.LEFT,
            JSplitPane.RIGHT,
            JSplitPane.TOP,
            JSplitPane.BOTTOM
        };

        public String[] getTags() {
            return values;
        }

        public String getAsText() {
            return (String)getValue();
        }

        public void setAsText(String str) {
            for (int i = 0; i < values.length; i++)
                if (str.equals(values[i])) {
                    setValue(str);
                    break;
                }
        }
    }
}
... 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.