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;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.undo.*;
import java.util.*;
import java.util.List;

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

/**
 *
 * @author Tran Duc Trung
 */

class ComponentDragger
{
    private FormDesigner formDesigner;
    private HandleLayer handleLayer;
    private RADVisualComponent[] selectedComponents;
    private Point hotspot;
    private Point mousePosition;
    private int resizeType;

    private RADVisualContainer targetMetaContainer;
    private boolean fixedTarget;

    private Container targetContainer;
    private Container targetContainerDel;

    /** The FormLoaderSettings instance */
    // constructor for dragging
    ComponentDragger(FormDesigner formDesigner,
                     HandleLayer handleLayer,
                     RADVisualComponent[] selectedComponents,
                     Point hotspot,
                     RADVisualContainer fixedTargetMetaContainer)
    {
        this.formDesigner = formDesigner;
        this.handleLayer = handleLayer;
        this.selectedComponents = selectedComponents;
        this.hotspot = hotspot;
        this.mousePosition = hotspot;
        this.resizeType = 0;

        if (fixedTargetMetaContainer != null) {
            targetMetaContainer = fixedTargetMetaContainer;
            fixedTarget = true;
        }
    }

    // constructor for resizing
    ComponentDragger(FormDesigner formDesigner,
                     HandleLayer handleLayer,
                     RADVisualComponent[] selectedComponents,
                     Point hotspot,
                     int resizeType)
    {
        this.formDesigner = formDesigner;
        this.handleLayer = handleLayer;
        this.selectedComponents = selectedComponents;
        this.hotspot = hotspot;
        this.mousePosition = hotspot;
        this.resizeType = resizeType;
    }

    void drag(Point p) {
        mousePosition = p;
    }

    void paintDragFeedback(Graphics2D g) {
        Stroke oldStroke = g.getStroke();
        Stroke stroke = new BasicStroke((float) 2.0,
                                        BasicStroke.CAP_SQUARE,
                                        BasicStroke.JOIN_MITER,
                                        (float) 10.0,
                                        new float[] { (float) 1.0, (float) 4.0 },
                                        0 );
        g.setStroke(stroke);

        Color oldColor = g.getColor();
        g.setColor(FormLoaderSettings.getInstance().getSelectionBorderColor());

        List constraints = new ArrayList(selectedComponents.length);
        List indices = new ArrayList(selectedComponents.length);

        boolean constraintsOK = computeConstraints(mousePosition,
                                                   constraints, indices);

        Point contPos = null;
        LayoutSupportManager layoutSupport = null;
        if (constraintsOK) {
            contPos = SwingUtilities.convertPoint(targetContainerDel, 0, 0, handleLayer);
            layoutSupport = targetMetaContainer.getLayoutSupport();
            if (resizeType == 0)
                paintTargetContainerFeedback(g, targetContainerDel);
        }

        for (int i = 0; i < selectedComponents.length; i++) {
            RADVisualComponent metacomp = selectedComponents[i];
            boolean drawn = false;

            if (constraintsOK) {
                Component comp = (Component) formDesigner.getComponent(metacomp);
                LayoutConstraints constr = (LayoutConstraints) constraints.get(i);
                int index = ((Integer)indices.get(i)).intValue();

                if (constr != null || index >= 0) {
                    g.translate(contPos.x, contPos.y);
                    drawn = layoutSupport.paintDragFeedback(
                                targetContainer, targetContainerDel,
                                comp, constr, index, g);
                    g.translate(- contPos.x, - contPos.y);
                }
//                else continue;
            }

            if (!drawn)
                paintDragFeedback(g, metacomp);
        }

        g.setColor(oldColor);
        g.setStroke(oldStroke);
    }

    void dropComponents(Point point) {
        List constraints = null; // constraints of the dragged components
        List indices = null; // indices of the dragged components

        if (targetMetaContainer != null) {
            constraints = new ArrayList(selectedComponents.length);
            indices = new ArrayList(selectedComponents.length);
            if (!computeConstraints(point, constraints, indices))
                return;
        }
        else if (handleLayer.mouseOnVisual(point))
            return;

        FormModel formModel = formDesigner.getModel();

        // LayoutSupportManager of the target container
        LayoutSupportManager layoutSupport = null;
        // original components in the target container
        RADVisualComponent[] originalComponents = null;
        LayoutConstraints[] originalConstraints = null;
        // components moved from other containers
        List movedFromOutside = null;
        // components moved within the target container
        List movedWithinTarget = null;

        if (targetMetaContainer != null) { // target is a visual container
            layoutSupport = targetMetaContainer.getLayoutSupport();
            originalComponents = targetMetaContainer.getSubComponents();
            originalConstraints =
                new LayoutConstraints[originalComponents.length];

            // adjust indices considering that some of dragged components
            // might be already in target container
            adjustIndices(indices);

            // collect components being dragged from other containers
            for (int i=0; i < selectedComponents.length; i++) {
                if (selectedComponents[i].getParentContainer()
                        != targetMetaContainer)
                {
                    if (movedFromOutside == null)
                        movedFromOutside = new ArrayList(selectedComponents.length);
                    movedFromOutside.add(new Integer(i)); // remember index
                }
                else {
                    if (movedWithinTarget == null)
                        movedWithinTarget = new ArrayList(selectedComponents.length);
                    movedWithinTarget.add(selectedComponents[i]);
                }
            }

            // test whether target container accepts new components (dragged
            // from other containers)
            if (movedFromOutside != null && movedFromOutside.size() > 0) {
                int count = movedFromOutside.size();
                RADVisualComponent[] newComps = new RADVisualComponent[count];
                LayoutConstraints[] newConstr = new LayoutConstraints[count];

                for (int i=0; i < count; i++) {
                    int index = ((Integer)movedFromOutside.get(i)).intValue();
                    newComps[i] = selectedComponents[index];
                    newConstr[i] = (LayoutConstraints) constraints.get(index);
                }

                // j - index to selectedComponents for the first new component
                int j = ((Integer)movedFromOutside.get(0)).intValue();
                // jj - insertion point of the first component in target container
                int jj = ((Integer)indices.get(j)).intValue();

                try {
                    layoutSupport.acceptNewComponents(newComps, newConstr, jj);
                }
                catch (RuntimeException ex) {
                    // layout support does not accept components
                    org.openide.ErrorManager.getDefault().notify(org.openide.ErrorManager.INFORMATIONAL, ex);
                    return;
                }

                // layout support might adjust the constraints
                for (int i=0; i < count; i++) {
                    int index = ((Integer)movedFromOutside.get(i)).intValue();
                    constraints.set(index, newConstr[i]);
                }

                movedFromOutside.clear(); // for later use
            }
        }

        // create list of components and constraints for target container
        int n = selectedComponents.length
                + (originalComponents != null ? originalComponents.length : 0);
        List newComponents = new ArrayList(n);
        List newConstraints = new ArrayList(n);
        int newI = 0;

        // fill enough empty space
        for (int i=0; i < n; i++) {
            newComponents.add(null);
            newConstraints.add(null);
        }

        if (targetMetaContainer != null) {
            // add dragged components requiring exact position (index)
            for (int i=0; i < selectedComponents.length; i++) {
                int index = ((Integer)indices.get(i)).intValue();
                if (index >= 0 && index < n && checkTarget(selectedComponents[i])) {
                    while (newComponents.get(index) != null) // ensure free index
                        if (++index == n)
                            index = 0;

                    newComponents.set(index, selectedComponents[i]);
                }
            }

            // add all components being already in the target container
            for (int i=0; i < originalComponents.length; i++) {
                RADVisualComponent metacomp = originalComponents[i];
                originalConstraints[i] = layoutSupport.getConstraints(metacomp);

                int index = newComponents.indexOf(metacomp);
                if (index < 0) { // not yet in newComponents
                    while (newComponents.get(newI) != null) // ensure free index
                        newI++;

                    newComponents.set(newI, metacomp);
                    newConstraints.set(newI, originalConstraints[i]);
                }
            }
        }

        // add the rest of dragged components (driven by constraints typically)
        for (int i=0; i < selectedComponents.length; i++) {
            RADVisualComponent metacomp = selectedComponents[i];
            int index = newComponents.indexOf(metacomp);
            if (index >= 0) { // already in newComponents
                newConstraints.set(index, constraints != null ?
                                              constraints.get(i) : null);
            }
            else if (checkTarget(metacomp)) { // not yet in newComponents
                while (newComponents.get(newI) != null) // ensure free index
                    newI++;

                newComponents.set(newI, metacomp);
                newConstraints.set(newI, constraints != null ?
                                             constraints.get(i) : null);
            }
        }
        // now we have lists of components and constraints in right order

        // remove components from source containers
        for (int i=0; i < n; i++) {
            RADVisualComponent metacomp = (RADVisualComponent) newComponents.get(i);
            if (metacomp != null) {
                RADVisualContainer parentCont = metacomp.getParentContainer();
                if (parentCont != targetMetaContainer) {
                    if (movedFromOutside == null)
                        movedFromOutside = new ArrayList(selectedComponents.length);
                    movedFromOutside.add(metacomp);

                    formModel.removeComponentFromContainer(metacomp);
                }
            }
            else { // remove empty space
                newComponents.remove(i);
                newConstraints.remove(i);
                i--;
                n--;
            }
        }

        if (n == 0)
            return; // dragging not allowed

        // turn off undo/redo monitoring in FormModel as we provide our own
        // undoable edit for the rest (adding part) of the operation
        boolean undoRedoOn = formModel.isUndoRedoRecording();
        if (undoRedoOn)
            formModel.setUndoRedoRecording(false);

        // prepare arrays of components and constraints (from lists)
        RADVisualComponent[] newCompsArray = new RADVisualComponent[n];
        LayoutConstraints[] newConstrArray = new LayoutConstraints[n];
        
        if (targetMetaContainer != null) { // target is a visual container
            for (int i=0; i < n; i++) {
                newCompsArray[i] = (RADVisualComponent) newComponents.get(i);
                newConstrArray[i] = (LayoutConstraints) newConstraints.get(i);
            }

            // clear the target layout
            layoutSupport.removeAll();

            // add all components to the target container
            targetMetaContainer.initSubComponents(newCompsArray);
            layoutSupport.addComponents(newCompsArray, newConstrArray, 0);
        }
        else { // no visual target, add the components to Other Components
            ComponentContainer othersMetaCont = formModel.getModelContainer();
            for (int i=0; i < n; i++) {
                newCompsArray[i] = (RADVisualComponent) newComponents.get(i);
                othersMetaCont.add(newCompsArray[i]);
            }
        }

        // fire changes - adding new components
        RADVisualComponent[] compsMovedFromOutside;
        if (movedFromOutside != null) {
            n = movedFromOutside.size();
            compsMovedFromOutside = new RADVisualComponent[n];
            for (int i=0; i < n; i++) {
                compsMovedFromOutside[i] = (RADVisualComponent)
                                           movedFromOutside.get(i);
                formModel.fireComponentAdded(compsMovedFromOutside[i], false);
            }
        }
        else {
            compsMovedFromOutside = new RADVisualComponent[0];
            formModel.fireComponentsReordered(targetMetaContainer, new int[0]);
        }

        // fire changes - changing components layout
        RADVisualComponent[] compsMovedWithinTarget;
        if (movedWithinTarget != null) {
            n = movedWithinTarget.size();
            compsMovedWithinTarget = new RADVisualComponent[n];
            for (int i=0; i < n; i++) {
                compsMovedWithinTarget[i] = (RADVisualComponent)
                                            movedWithinTarget.get(i);
                formModel.fireComponentLayoutChanged(compsMovedWithinTarget[i],
                                                     null, null, null);
            }
        }
        else compsMovedWithinTarget = new RADVisualComponent[0];

        // setup undoable edit
        if (undoRedoOn) {
            DropUndoableEdit dropUndo = new DropUndoableEdit();
            dropUndo.formModel = formModel;
            dropUndo.targetContainer = targetMetaContainer;
            dropUndo.targetComponentsBeforeMove = originalComponents;
            dropUndo.targetConstraintsBeforeMove = originalConstraints;
            dropUndo.targetComponentsAfterMove = newCompsArray;
            dropUndo.targetConstraintsAfterMove = newConstrArray;
            dropUndo.componentsMovedFromOutside = compsMovedFromOutside;
            dropUndo.componentsMovedWithinTarget = compsMovedWithinTarget;

            formModel.addUndoableEdit(dropUndo);
        }

        // finish undoable edit
        if (undoRedoOn) // turn on undo/redo monitoring again
            formModel.setUndoRedoRecording(true);

        // select dropped components in designer (after everything updates)
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                formDesigner.setSelectedComponents(selectedComponents);
            }
        });
    }

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

    private boolean computeConstraints(Point p, List constraints, List indices) {
        if (selectedComponents == null || selectedComponents.length == 0)
            return false;

        if (!fixedTarget) {
            targetMetaContainer = resizeType == 0 ?
                                    handleLayer.getMetaContainerAt(p) :
                                    selectedComponents[0].getParentContainer();
            if (targetMetaContainer == null)
                return false; // unknown meta-container
        }

        RADVisualContainer fixTargetContainer = null;
        do {
            if (fixTargetContainer != null) {
                targetMetaContainer = fixTargetContainer;
                fixTargetContainer = null;
            }

            LayoutSupportManager layoutSupport = targetMetaContainer.getLayoutSupport();
//            if (layoutSupport == null)
//                return false; // no LayoutSupport (should not happen)

            targetContainer = (Container) formDesigner.getComponent(targetMetaContainer);
            if (targetContainer == null)
                return false; // container not in designer (should not happen)

            targetContainerDel = targetMetaContainer.getContainerDelegate(targetContainer);
            if (targetContainerDel == null)
                return false; // no container delegate (should not happen)

            Point posInCont = SwingUtilities.convertPoint(handleLayer, p, targetContainerDel);

            for (int i = 0; i < selectedComponents.length; i++) {
                LayoutConstraints constr = null;
                int index = -1;

                RADVisualComponent metacomp = selectedComponents[i];
                Component comp = (Component) formDesigner.getComponent(metacomp);

                if (comp != null) {
                    if (!checkTarget(metacomp)) {
                        fixTargetContainer = metacomp.getParentContainer();
                        constraints.clear();
                        indices.clear();
                        if (fixTargetContainer == null)
                            return false; // should not happen
                        break;
                    }

                    if (resizeType == 0) { // dragging
                        Point posInComp = SwingUtilities.convertPoint(
                                              handleLayer, hotspot, comp);
                        index = layoutSupport.getNewIndex(
                                    targetContainer, targetContainerDel,
                                    comp, metacomp.getComponentIndex(),
                                    posInCont, posInComp);
                        constr = layoutSupport.getNewConstraints(
                                    targetContainer, targetContainerDel,
                                    comp, metacomp.getComponentIndex(),
                                    posInCont, posInComp);

                        if (constr == null && index >= 0) {
                            // keep old constraints (if compatible)
                            LayoutSupportManager.storeConstraints(metacomp);
                            constr = layoutSupport.getStoredConstraints(metacomp);
                        }
                    }
                    else { // resizing
                        int up = 0, down = 0, left = 0, right = 0;

                        if ((resizeType & LayoutSupportManager.RESIZE_DOWN) != 0)
                            down = p.y - hotspot.y;
                        else if ((resizeType & LayoutSupportManager.RESIZE_UP) != 0)
                            up = hotspot.y - p.y;
                        if ((resizeType & LayoutSupportManager.RESIZE_RIGHT) != 0)
                            right = p.x - hotspot.x;
                        else if ((resizeType & LayoutSupportManager.RESIZE_LEFT) != 0)
                            left = hotspot.x - p.x;

                        Insets sizeChanges = new Insets(up, left, down, right);
                        constr = layoutSupport.getResizedConstraints(
                                     targetContainer, targetContainerDel,
                                     comp, metacomp.getComponentIndex(),
                                     sizeChanges, posInCont);
                    }
                }

                constraints.add(constr);
                indices.add(new Integer(index));
            }
        }
        while (fixTargetContainer != null);

        return true;
    }

    /** Checks whether metacomp is not a parent of target container (or the
     * target container itself). Used to avoid dragging to a sub-tree.
     * @return true if metacomp is OK
     */
    private boolean checkTarget(RADVisualComponent metacomp) {
        if (!(metacomp instanceof RADVisualContainer))
            return true;

        RADComponent targetCont = targetMetaContainer;
        while (targetCont != null) {
            if (targetCont == metacomp)
                return false;
            targetCont = targetCont.getParentComponent();
        }

        return true;
    }

    /** Modifies suggested indices of dragged components considering the fact
     * that some of the components might be in the target container.
     */
    private void adjustIndices(List indices) {
        int index;
        int correction;
        int prevIndex = -1;
        int prevCorrection = 0;

        for (int i=0; i < indices.size(); i++) {
            index = ((Integer)indices.get(i)).intValue();
            if (index >= 0) {
                if (index == prevIndex) {
                    correction = prevCorrection;
                }
                else {
                    correction = 0;
                    RADVisualComponent[] targetComps =
                                         targetMetaContainer.getSubComponents();
                    for (int j=0; j < index; j++) {
                        RADVisualComponent tComp = targetComps[j];
                        boolean isSelected = false;
                        for (int k=0; k < selectedComponents.length; k++)
                            if (tComp == selectedComponents[k]) {
                                isSelected = true;
                                break;
                            }

                        if (isSelected)
                            correction++;
                    }
                    prevIndex = index;
                    prevCorrection = correction;
                }

                if (correction != 0) {
                    index -= correction;
                    indices.set(i, new Integer(index));
                }
            }
        }
    }

    private void paintDragFeedback(Graphics2D g, RADVisualComponent metacomp) {
        Object comp = formDesigner.getComponent(metacomp);
        if (!(comp instanceof Component) || !((Component)comp).isShowing())
            return;

        Component component = (Component) comp;

        Rectangle rect = component.getBounds();
        rect = SwingUtilities.convertRectangle(component.getParent(),
                                               rect,
                                               handleLayer);

        rect.translate(mousePosition.x - hotspot.x,
                       mousePosition.y - hotspot.y);
        
        g.draw(new Rectangle2D.Double(rect.x, rect.y, rect.width, rect.height));

        if (metacomp instanceof RADVisualContainer) {
            RADVisualComponent[] children =
                ((RADVisualContainer)metacomp).getSubComponents();
            for (int i = 0; i < children.length; i++) {
                paintDragFeedback(g, children[i]);
            }
        }
    }

    private void paintTargetContainerFeedback(Graphics2D g, Container cont) {
        Stroke oldStroke = g.getStroke();
        Stroke stroke = new BasicStroke((float) 2.0,
                                        BasicStroke.CAP_SQUARE,
                                        BasicStroke.JOIN_MITER,
                                        (float) 10.0,
                                        new float[] { (float) 2.0, (float) 8.0 },
                                        0 );
        g.setStroke(stroke);

        Color oldColor = g.getColor();
        g.setColor(FormLoaderSettings.getInstance().getDragBorderColor());
        
        Rectangle rect = new Rectangle(new Point(0,0), cont.getSize());
        rect = SwingUtilities.convertRectangle(cont,
                                               rect,
                                               handleLayer);
        g.draw(new Rectangle2D.Double(rect.x, rect.y, rect.width, rect.height));
        g.setColor(oldColor);
        g.setStroke(oldStroke);
    }

    // ---------

    private static class DropUndoableEdit extends AbstractUndoableEdit {

        FormModel formModel;
        RADVisualContainer targetContainer;
        RADVisualComponent[] targetComponentsBeforeMove;
        LayoutConstraints[] targetConstraintsBeforeMove;
        RADVisualComponent[] targetComponentsAfterMove;
        LayoutConstraints[] targetConstraintsAfterMove;
        RADVisualComponent[] componentsMovedFromOutside;
        RADVisualComponent[] componentsMovedWithinTarget;

        public void undo() throws CannotUndoException {
            super.undo();

            // turn off undo/redo monitoring in FormModel while undoing!
            boolean undoRedoOn = formModel.isUndoRedoRecording();
            if (undoRedoOn)
                formModel.setUndoRedoRecording(false);

            for (int i=0; i < componentsMovedFromOutside.length; i++)
                formModel.removeComponentFromContainer(
                                         componentsMovedFromOutside[i]);

            if (targetContainer != null) {
                LayoutSupportManager layoutSupport =
                    targetContainer.getLayoutSupport();
                layoutSupport.removeAll();
                targetContainer.initSubComponents(targetComponentsBeforeMove);
                layoutSupport.addComponents(targetComponentsBeforeMove,
                                            targetConstraintsBeforeMove,
                                            0);

                for (int i=0; i < componentsMovedWithinTarget.length; i++)
                    formModel.fireComponentLayoutChanged(
                        componentsMovedWithinTarget[i], null, null, null);
            }

            if (undoRedoOn) // turn on undo/redo monitoring again
                formModel.setUndoRedoRecording(true);
        }

        public void redo() throws CannotRedoException {
            super.redo();

            // turn off undo/redo monitoring in FormModel while redoing!
            boolean undoRedoOn = formModel.isUndoRedoRecording();
            if (undoRedoOn)
                formModel.setUndoRedoRecording(false);

            if (targetContainer != null) {
                LayoutSupportManager layoutSupport =
                    targetContainer.getLayoutSupport();
                layoutSupport.removeAll();
                targetContainer.initSubComponents(targetComponentsAfterMove);
                layoutSupport.addComponents(targetComponentsAfterMove,
                                            targetConstraintsAfterMove,
                                            0);
            }
            else {
                ComponentContainer othersMetaCont = formModel.getModelContainer();
                for (int i=0; i < targetComponentsAfterMove.length; i++)
                    othersMetaCont.add(targetComponentsAfterMove[i]);
            }

            for (int i=0; i < componentsMovedFromOutside.length; i++)
                formModel.fireComponentAdded(componentsMovedFromOutside[i],
                                             false);

            for (int i=0; i < componentsMovedWithinTarget.length; i++)
                formModel.fireComponentLayoutChanged(
                    componentsMovedWithinTarget[i], null, null, null);

            if (undoRedoOn) // turn on undo/redo monitoring again
                formModel.setUndoRedoRecording(true);
        }

        public String getUndoPresentationName() {
            return ""; // NOI18N
        }
        public String getRedoPresentationName() {
            return ""; // NOI18N
        }
    }
}
... 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.