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 java.util.*;
import java.text.MessageFormat;

import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.StatusDisplayer;
import org.openide.windows.TopComponent;
import org.openide.nodes.Node;
import org.openide.nodes.NodeOp;

import org.netbeans.modules.form.palette.CPManager;
import org.netbeans.modules.form.palette.PaletteItem;

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

/**
 * A transparent layer (glass pane) handling user operations in designer (mouse
 * and keyboard events) and painting selection and drag&drop feedback.
 * Technically, this is a layer in FormDesigner, placed over ComponentLayer.
 *
 * @author Tran Duc Trung, Tomas Pavek
 */

class HandleLayer extends JPanel
{
    // constants for mode parameter of getMetaComponentAt(Point,int) method
    static final int COMP_DEEPEST = 0; // get the deepest component (at given point)
    static final int COMP_SELECTED = 1; // get the deepest selected component
    static final int COMP_ABOVE_SELECTED = 2; // get the component above the deepest selected component
    static final int COMP_UNDER_SELECTED = 3; // get the component under the deepest selected component

    private static final int DESIGNER_RESIZING = 256; // flag for resizeType
    private static MessageFormat resizingHintFormat;

    private FormDesigner formDesigner;
    private boolean viewOnly;

    private ComponentDragger componentDragger;
    private Point lastLeftMousePoint;
    private Point prevLeftMousePoint;
    private boolean draggingCanceled = false;
    private int resizeType;

    private SelectionDragger selectionDragger;

    private DesignerResizer designerResizer;

    /** The FormLoaderSettings instance */
    private static FormLoaderSettings formSettings = FormLoaderSettings.getInstance();


    HandleLayer(FormDesigner fd) {
        formDesigner = fd;
        addMouseListener(new HandleLayerMouseListener());
        addMouseMotionListener(new HandleLayerMouseMotionListener());
//        setNextFocusableComponent(this);
        setLayout(null);

        // set Ctrl+TAB and Ctrl+Shift+TAB as focus traversal keys - to have
        // TAB and Shift+TAB free for component selection
        Set keys = new HashSet();
        keys.add(AWTKeyStroke.getAWTKeyStroke(9,
                                              InputEvent.CTRL_DOWN_MASK,
                                              true));
        setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
                              keys);
        keys.clear();
        keys.add(AWTKeyStroke.getAWTKeyStroke(9,
                                              InputEvent.CTRL_DOWN_MASK
                                                 |InputEvent.SHIFT_DOWN_MASK,
                                              true));
        setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
                              keys);

        getAccessibleContext().setAccessibleName(
            FormUtils.getBundleString("ACSN_HandleLayer")); // NOI18N
        getAccessibleContext().setAccessibleDescription(
            FormUtils.getBundleString("ACSD_HandleLayer")); // NOI18N
    }

    void setViewOnly(boolean viewOnly) {
        this.viewOnly = viewOnly;
    }

    protected void paintComponent(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;

        g2.setStroke(new BasicStroke(formSettings.getSelectionBorderSize()));

        RADComponent conSource = formDesigner.getConnectionSource();
        RADComponent conTarget = formDesigner.getConnectionTarget();
        if (conSource != null || conTarget != null) {
            // paint connection
            g2.setColor(formSettings.getConnectionBorderColor());
            if (conSource != null)
                paintSelection(g2, conSource);
            if (conTarget != null)
                paintSelection(g2, conTarget);
        }
        else {
            // paint selection
            g2.setColor(formSettings.getSelectionBorderColor());
            Iterator metacomps = formDesigner.getSelectedComponents().iterator();
            while (metacomps.hasNext()) {
                paintSelection(g2, (RADComponent) metacomps.next());
            }
        }

        if (componentDragger != null)
            componentDragger.paintDragFeedback(g2);
        if (selectionDragger != null)
            selectionDragger.paintDragFeedback(g2);
    }

    private void paintSelection(Graphics2D g, RADComponent metacomp) {
        Object comp = formDesigner.getComponent(metacomp);
        if (!(comp instanceof Component))
            return;

        Component component = (Component) comp;
        Component parent = component.getParent();

        if (parent != null && component.isShowing()) {
            Rectangle rect = component.getBounds();
            rect = SwingUtilities.convertRectangle(parent, rect, this);

            Rectangle parentRect = new Rectangle(new Point(0,0),
                                                 parent.getSize());
            parentRect = SwingUtilities.convertRectangle(parent,
                                                         parentRect,
                                                         this);

            Rectangle2D selRect = rect.createIntersection(parentRect);

            int correction = formSettings.getSelectionBorderSize() % 2;
            g.draw(new Rectangle2D.Double(
                selRect.getX() - correction,
                selRect.getY() - correction,
                selRect.getWidth() + correction,
                selRect.getHeight() + correction));
        }
    }

    public boolean isOpaque() {
        return false;
    }

    protected void processKeyEvent(KeyEvent e) {
        int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_TAB || e.getKeyChar() == '\t') {
            if (!e.isControlDown()) {
                if (e.getID() == KeyEvent.KEY_PRESSED) {
                    RADComponent nextComp = formDesigner.getNextVisualComponent(
                                                              !e.isShiftDown());
                     if (nextComp != null)
                         formDesigner.setSelectedComponent(nextComp);
                }
                e.consume();
                return;
            }
        }
        else if (keyCode == KeyEvent.VK_SPACE) {
            if (!viewOnly && e.getID() == KeyEvent.KEY_RELEASED) {
                Iterator it = formDesigner.getSelectedComponents().iterator();
                if (it.hasNext()) {
                    RADComponent comp = (RADComponent)it.next();
                    if (!it.hasNext()) { // just one component is selected
                        if (formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT) {
                            // in selection mode SPACE starts in-place editing
                            formDesigner.startInPlaceEditing(comp);
                        }
                        else if (formDesigner.getDesignerMode() == FormDesigner.MODE_ADD) {
                            // in add mode SPACE adds selected item as component
                            PaletteItem item = CPManager.getDefault().getSelectedItem();
                            if (item != null) {
                                formDesigner.getModel().getComponentCreator()
                                    .createComponent(item.getComponentClassSource(),
                                                     comp,
                                                     null);
                                formDesigner.toggleSelectionMode();
                            }
                        }
                    }
                }
            }
            e.consume();
            return;
        }
        else if (keyCode == KeyEvent.VK_ESCAPE) {
            if (endDragging(null))
                e.consume();
                return;
        }
        else if (keyCode == KeyEvent.VK_F10) {
            if (e.isShiftDown()) {
                Point p = null;
                Iterator it = formDesigner.getSelectedComponents().iterator();
                if (it.hasNext()) {
                    RADComponent metacomp = (RADComponent)it.next();
                    Object sel = (Component) formDesigner.getComponent(metacomp);
                    if (sel instanceof Component) {
                        Component comp = (Component) sel;
                        p = SwingUtilities.convertPoint(comp.getParent(),
                                                        comp.getLocation(),
                                                        this);
                    }
                    else p = new Point(0,0);

                    showContextMenu(p);
                    e.consume();
                    return;
                }
            }
        }
//        else {
        super.processKeyEvent(e);
//        }
    }

    public boolean isFocusTraversable() {
        return true;
    }

    /**
     * Returns metacomponent at given position.
     * @param point - position on component layer
     * @param mode - what to get:
     *   COMP_DEEPEST - get the deepest component
     *   COMP_SELECTED - get the deepest selected component
     *   COMP_ABOVE_SELECTED - get the component above the deepest selected component
     *   COMP_UNDER_SELECTED - get the component under the deepest selected component
     * @returns the metacomponent at given point
     *   If no component is currently selected then:
     *     for COMP_SELECTED the deepest component is returned
     *     for COMP_ABOVE_SELECTED the deepest component is returned
     *     for COMP_UNDER_SELETCED the top component is returned
     */
    private RADComponent getMetaComponentAt(Point point, int mode) {
        Component[] deepComps = getDeepestComponentsAt(
                                    formDesigner.getComponentLayer(), point);
        if (deepComps.length == 0)
            return null;

        int dIndex = mode == COMP_DEEPEST ? deepComps.length - 1 : 0;
        Component comp = deepComps[dIndex];

        // find the component satisfying point and mode
        RADComponent topMetaComp = formDesigner.getTopDesignComponent();
        RADComponent firstMetaComp = null;
        RADComponent currMetaComp;
        RADComponent prevMetaComp = null;

        do {
            currMetaComp = formDesigner.getMetaComponent(comp);
            if (currMetaComp != null) {
                if (firstMetaComp == null)
                    firstMetaComp = currMetaComp;

                switch (mode) {
                    case COMP_DEEPEST: 
                        return currMetaComp;

                    case COMP_SELECTED:
                        if (formDesigner.isComponentSelected(currMetaComp))
                            return currMetaComp;
                        if (currMetaComp == topMetaComp)
                            return firstMetaComp; // nothing selected - return the deepest
                        break;

                    case COMP_ABOVE_SELECTED:
                        if (prevMetaComp != null 
                                && formDesigner.isComponentSelected(prevMetaComp))
                            return currMetaComp;
                        if (currMetaComp == topMetaComp)
                            return firstMetaComp; // nothing selected - return the deepest
                        break;

                    case COMP_UNDER_SELECTED:
                        if (formDesigner.isComponentSelected(currMetaComp))
                            return prevMetaComp != null ?
                                     prevMetaComp : topMetaComp;
                        if (currMetaComp == topMetaComp)
                            return topMetaComp; // nothing selected - return the top
                        break;
                }

                prevMetaComp = currMetaComp;
            }

            comp = dIndex + 1 < deepComps.length ?
                   deepComps[++dIndex] : comp.getParent();
        }
        while (comp != null);

        return firstMetaComp;
    }

    private static Component[] getDeepestComponentsAt(Container parent,
                                                      Point point)
    {
        Component comp = SwingUtilities.getDeepestComponentAt(parent,
                                                              point.x,
                                                              point.y);
        if (comp == null)
            return new Component[0];

        Container deepestParent = comp.getParent();
        Component[] deepestComponents = deepestParent.getComponents();
        Point deepestPosition =
            SwingUtilities.convertPoint(parent, point, deepestParent);

        // in most cases there will be just one component...
        Component[] componentsAtPoint = new Component[1];
        ArrayList compList = null;

        for (int i=0; i < deepestComponents.length; i++) {
            comp = deepestComponents[i];
            Point p = comp.getLocation();
            if (comp.isVisible()
                && comp.contains(deepestPosition.x - p.x,
                                 deepestPosition.y - p.y))
            {
                if (componentsAtPoint[0] == null)
                    componentsAtPoint[0] = comp;
                else {
                    if (compList == null) {
                        compList = new ArrayList();
                        compList.add(componentsAtPoint[0]);
                    }
                    compList.add(comp);
                }
            }
        }

        if (compList == null)
            return componentsAtPoint[0] != null ?
                     componentsAtPoint : new Component[0];

        componentsAtPoint = new Component[compList.size()];
        compList.toArray(componentsAtPoint);
        return componentsAtPoint;
    }

    RADVisualContainer getMetaContainerAt(Point point) {
        RADComponent metacomp = getMetaComponentAt(point, COMP_DEEPEST);
        if (metacomp == null)
            return null;
        if (metacomp instanceof RADVisualContainer)
            return (RADVisualContainer) metacomp;
        if (metacomp instanceof RADVisualComponent)
            return (RADVisualContainer) metacomp.getParentComponent();
        return null;
    }

    /** Selects component at the position e.getPoint() on component layer.
     * What component is selected further depends on whether CTRL or ALT
     * keys are hold. */
    private RADComponent selectComponent(MouseEvent e) {
        int selMode = !e.isAltDown() ? COMP_DEEPEST :
                (!e.isShiftDown() ? COMP_ABOVE_SELECTED : COMP_UNDER_SELECTED);

        RADComponent hitMetaComp = getMetaComponentAt(e.getPoint(), selMode);

        if (e.isControlDown()) {
            // Control is pressed - add component to selection
            if (hitMetaComp != null)
                if (formDesigner.isComponentSelected(hitMetaComp))
                    formDesigner.removeComponentFromSelection(hitMetaComp);
                else
                    formDesigner.addComponentToSelection(hitMetaComp);
        }
        else if (e.isShiftDown() && !e.isAltDown()) {
            // Shift is pressed - select interval
            if (hitMetaComp != null
                && !formDesigner.isComponentSelected(hitMetaComp))
            {
                if (formDesigner.getSelectedComponents().size() > 0) {
                    RADComponent[] intervalToSelect =
                        getComponentsIntervalToSelect(hitMetaComp, false);
                    if (intervalToSelect == null)
                        intervalToSelect = getComponentsIntervalToSelect(
                                                       hitMetaComp, true);
                    if (intervalToSelect != null)
                        formDesigner.setSelectedComponents(intervalToSelect);
                    else
                        formDesigner.setSelectedComponent(hitMetaComp);
                }
                else
                    formDesigner.setSelectedComponent(hitMetaComp);
            }
        }
        else { // no reasonable modifier key pressed - select single component
            if (hitMetaComp != null) {
                if (!formDesigner.isComponentSelected(hitMetaComp))
                    formDesigner.setSelectedComponent(hitMetaComp);
            }
            else formDesigner.clearSelection();
        }

        return hitMetaComp;
    }

    private RADComponent[] getComponentsIntervalToSelect(
                             RADComponent clickedComp,
                             boolean forward)
    {
        if (!(clickedComp instanceof RADVisualComponent))
            return null;

        java.util.List toSelect = new LinkedList();
        RADVisualComponent comp = (RADVisualComponent) clickedComp;
        boolean selected = false;

        do  // starting with clickedComp,
        {   // go forward/backward in components until a selected one is reached
            if (forward)
                toSelect.add(comp);
            else
                toSelect.add(0, comp);

            comp = formDesigner.getNextVisualComponent(comp, forward);
        }
        while (comp != null && comp != clickedComp
               && !(selected = formDesigner.isComponentSelected(comp))
               && comp != formDesigner.getTopDesignComponent());

        if (selected) { // selected component found - we can make the interval
            if (comp == formDesigner.getTopDesignComponent()) {
                if (!forward) // top component is fine when going backward
                    toSelect.add(0, comp);
            }
            else { // add also already selected components in the direction
                selected = false;
                do {
                    if (forward)
                        toSelect.add(comp);
                    else
                        toSelect.add(0, comp);

                    comp = formDesigner.getNextVisualComponent(comp, forward);
                }
                while (comp != null
                       && (selected = formDesigner.isComponentSelected(comp))
                       && comp != formDesigner.getTopDesignComponent());

                if (selected && !forward)
                    toSelect.add(0, comp); // top comp is fine when going backward
            }            

            RADComponent[] compArray = new RADComponent[toSelect.size()];
            toSelect.toArray(compArray);
            return compArray;
        }

        return null;
    }

    private void selectOtherComponentsNode() {
        FormEditorSupport fes = formDesigner.getFormEditorSupport();
        ComponentInspector ci = ComponentInspector.getInstance();
        Node[] selectedNode = new Node[] {
            ((FormRootNode)fes.getFormRootNode()).getOthersNode() };
        
        try {
            ci.setSelectedNodes(selectedNode, fes);
            formDesigner.clearSelectionImpl();
            formDesigner.repaintSelection();
        }
        catch (java.beans.PropertyVetoException ex) {
            ex.printStackTrace();
        }

        formDesigner.setActivatedNodes(selectedNode);
    }

    private boolean processDoubleClick(MouseEvent e) {
        if (e.isShiftDown() || e.isControlDown())
            return false;

        RADComponent metacomp = getMetaComponentAt(e.getPoint(), COMP_SELECTED);
        if (metacomp == null)
            return true;

        if (e.isAltDown()) {
             if (metacomp == formDesigner.getTopDesignComponent()) {
                metacomp = metacomp.getParentComponent();
                if (metacomp == null)
                    return true;
            }
             else return false;
        }

        Node node = metacomp.getNodeReference();
        if (node != null) {
            Action action = node.getPreferredAction();
            if (action != null) {// && action.isEnabled()) {
                action.actionPerformed(new ActionEvent(
                        node, ActionEvent.ACTION_PERFORMED, "")); // NOI18N
            }
        }

        return true;
    }

    private void processMouseClickInLayoutSupport(RADComponent metacomp,
                                                  MouseEvent e)
    {
        if (!(metacomp instanceof RADVisualComponent))
            return;

        RADVisualContainer metacont;
        if (metacomp instanceof RADVisualContainer)
            metacont = (RADVisualContainer) metacomp;
        else {
            metacont = (RADVisualContainer) metacomp.getParentComponent();
            if (metacont == null)
                return;
        }

        Container cont = (Container) formDesigner.getComponent(metacont);
        Container contDelegate = metacont.getContainerDelegate(cont);
        Point p = SwingUtilities.convertPoint(HandleLayer.this,
                                              e.getPoint(),
                                              contDelegate);
        metacont.getLayoutSupport().processMouseClick(p, cont, contDelegate);
    }

    private void showContextMenu(Point popupPos) {
        ComponentInspector inspector = ComponentInspector.getInstance();
        TopComponent activated = TopComponent.getRegistry().getActivated();
        if (activated != formDesigner.multiViewObserver.getTopComponent()
                && activated != inspector)
            return;

        formDesigner.componentActivated(); // just for sure...

        Node[] selectedNodes = inspector.getSelectedNodes();
        JPopupMenu popup = NodeOp.findContextMenu(selectedNodes);
        if (popup != null) {
            popup.show(HandleLayer.this, popupPos.x, popupPos.y);
        }
    }

    // --------

    boolean anyDragger() {
        return componentDragger != null
               || selectionDragger != null
               || designerResizer != null;
    }

    private ComponentDragger createComponentDragger(Point hotspot,
                                                    int modifiers)
    {
        java.util.List selectedComponents = formDesigner.getSelectedComponents();
        if (selectedComponents.size() == 0)
            return null;

        // all selected components must be visible in the designer
        java.util.List selComps = new ArrayList(selectedComponents.size());
        Iterator iter = selectedComponents.iterator();
        while (iter.hasNext()) {
            RADComponent metacomp = (RADComponent) iter.next();
            if (metacomp instanceof RADVisualComponent)
                if (metacomp != formDesigner.getTopDesignComponent())
                    selComps.add(metacomp);
                else return null;
        }

        // remove selected components contained in another selected components
        Set children = new HashSet();
        iter = selComps.iterator();
        while (iter.hasNext()) {
            RADComponent metacomp = (RADComponent) iter.next();
            Iterator iter2 = selComps.iterator();
            while (iter2.hasNext()) {
                RADComponent metacomp2 = (RADComponent) iter2.next();
                if (metacomp2 != metacomp
                        && metacomp.isParentComponent(metacomp2))
                    children.add(metacomp2);
            }
        }
        selComps.removeAll(children);
        if (selComps.isEmpty())
            return null;

        RADVisualComponent[] comps = new RADVisualComponent[selComps.size()];
        selComps.toArray(comps);

        if (resizeType == 0) { // dragging
            RADVisualContainer fixedTargetContainer = null;

            if ((modifiers & InputEvent.ALT_MASK) != 0) { // restricted dragging
                RADVisualContainer parent = comps[0].getParentContainer();
                if ((modifiers & InputEvent.SHIFT_MASK) != 0
                    || formDesigner.getTopDesignComponent() == parent)
                {   // restrict dragging only to the parent container
                    // (dragging within the same container)
                    for (int i=1; i < comps.length; i++)
                        if (comps[i].getParentContainer() != parent) {
                            parent = null; // not the same parent
                            break;
                        }
                    fixedTargetContainer = parent;
                }
                else if ((parent = parent.getParentContainer()) != null) {
                    // restrict dragging only to the parent of the parent
                    // container (dragging one level up)
                    for (int i=1; i < comps.length; i++)
                        if (comps[i].getParentContainer().getParentContainer()
                                != parent)
                        {
                            parent = null;
                            break;
                        }
                    fixedTargetContainer = parent;
                }
            }

            return new ComponentDragger(formDesigner, this,
                                        comps, hotspot, fixedTargetContainer);
        }
        else // resizing
            return new ComponentDragger(formDesigner, this,
                                        comps, hotspot, resizeType);
    }

    private boolean endDragging(Point commitPosition) {
        if (anyDragger()) {
            if (resizeType != 0) {
                resizeType = 0;
                Cursor cursor = getCursor();
                if (cursor != null && cursor.getType() != Cursor.DEFAULT_CURSOR)
                    setCursor(Cursor.getDefaultCursor());
                if (getToolTipText() != null)
                    setToolTipText(null);
            }

            if (designerResizer != null) {
                if (commitPosition != null)
                    designerResizer.drop(commitPosition);
                else {
                    Dimension prevSize = formDesigner.getStoredDesignerSize();
                    if (!formDesigner.getComponentLayer().getDesignerSize()
                            .equals(prevSize))
                    {   // restore the previous designer size
                        formDesigner.getComponentLayer()
                                      .updateDesignerSize(prevSize);
                    }
                }
                designerResizer = null;
            }

            if (componentDragger != null) {
                if (commitPosition != null)
                    componentDragger.dropComponents(commitPosition);
                componentDragger = null;
                repaint();
            }

            if (selectionDragger != null) {
                if (commitPosition != null)
                    selectionDragger.drop(commitPosition);
                selectionDragger = null;
                repaint();
            }

            draggingCanceled = commitPosition == null;
            return true;
        }

        return false;
    }

    // Check the mouse cursor if it is at position where a component or the
    // designer can be resized. Change mouse cursor accordingly.
    private void checkResizing(MouseEvent e) {
        int resizing = checkComponentsResizing(e);
        if (resizing == 0) {
            resizing = checkDesignerResizing(e);
            if (resizing == 0) {
                if (getToolTipText() != null)
                    setToolTipText(null);
            }
            else if (getToolTipText() == null) {
                Dimension size = formDesigner.getComponentLayer()
                                               .getDesignerSize();
                if (resizingHintFormat == null)
                    resizingHintFormat = new MessageFormat(
                        FormUtils.getBundleString("FMT_HINT_DesignerResizing")); // NOI18N
                String hint = resizingHintFormat.format(
                                new Object[] { new Integer(size.width),
                                               new Integer(size.height) });
                setToolTipText(hint);
                ToolTipManager.sharedInstance().mouseEntered(e);
            }
        }
        else if (getToolTipText() != null)
            setToolTipText(null);

        if (resizing != 0)
            setResizingCursor(resizing);
        else {
            Cursor cursor = getCursor();
            if (cursor != null && cursor.getType() != Cursor.DEFAULT_CURSOR)
                setCursor(Cursor.getDefaultCursor());
        }
    }

    // Check the mouse cursor if it is at position where designer can be
    // resized.
    private int checkDesignerResizing(MouseEvent e) {
        if (!e.isAltDown() && !e.isControlDown() && !e.isShiftDown()) {
            ComponentLayer compLayer = formDesigner.getComponentLayer();
            int resizing = getSelectionResizable(
                             e.getPoint(),
                             compLayer.getComponentContainer(),
                             compLayer.getDesignerOutsets().right + 2);

            resizeType = validDesignerResizing(resizing) ?
                         resizing | DESIGNER_RESIZING : 0;
        }
        else resizeType = 0;

        return resizeType;
    }

    // Check whether given resize type is valid for designer.
    private boolean validDesignerResizing(int resizing) {
        return resizing == (LayoutSupportManager.RESIZE_DOWN
                            | LayoutSupportManager.RESIZE_RIGHT)
            || resizing == LayoutSupportManager.RESIZE_DOWN
            || resizing == LayoutSupportManager.RESIZE_RIGHT;
    }

    // Check the mouse cursor if it is at position where a component (or more
    // components) can be resized.
    private int checkComponentsResizing(MouseEvent e) {
        if (e.isAltDown() || e.isControlDown() || e.isShiftDown()) {
            resizeType = 0;
            return resizeType;
        }

        // check whether all selected components are in the same container
        RADComponent parent = null;
        Iterator selected = formDesigner.getSelectedComponents().iterator();
        while (selected.hasNext()) {
            RADComponent comp = (RADComponent) selected.next();
            if (comp instanceof RADVisualComponent) {
                if (parent == null) {
                    parent = comp.getParentComponent();
                    if (parent == null)
                        return 0; // component without a parent cannot be resized
                }
                else if (comp.getParentComponent() != parent)
                    return 0; // selected components are not in the same container
            }
        }

        Point p = e.getPoint();
        RADComponent compAtPoint = getMetaComponentAt(p, COMP_SELECTED);
        if (compAtPoint instanceof RADVisualComponent) {
            RADVisualComponent metacomp = (RADVisualComponent) compAtPoint;
            if (!formDesigner.isComponentSelected(metacomp)) {
                int resizing = 0;
                RADVisualComponent[] otherComps;
                if (metacomp instanceof RADVisualContainer)
                    otherComps = ((RADVisualContainer)metacomp).getSubComponents();
                else {
                    RADVisualContainer metacont = metacomp.getParentContainer();
                    if (metacont != null)
                        otherComps = metacont.getSubComponents();
                    else return 0; // component without a parent
                }

                for (int i=0; i < otherComps.length; i++) {
                    metacomp = otherComps[i];
                    resizing = getComponentResizable(p, metacomp);
                    if (resizing != 0)
                        break;
                }
                resizeType = resizing;
            }
            else resizeType = getComponentResizable(p, metacomp);
        }
        else resizeType = 0;

        return resizeType;
    }

    // Check how possible component resizing (obtained from layout support)
    // matches with mouse position on component selection border. 
    private int getComponentResizable(Point p, RADVisualComponent metacomp) {
        if (!formDesigner.isComponentSelected(metacomp))
            return 0;

        RADVisualContainer metacont = (RADVisualContainer)
                                      metacomp.getParentComponent();
        if (metacont == null
                || metacomp == formDesigner.getTopDesignComponent())
            return 0;

        LayoutSupportManager laySup = metacont.getLayoutSupport();
        if (laySup == null)
            return 0;

        Container cont = (Container) formDesigner.getComponent(metacont);
        Container contDel = metacont.getContainerDelegate(cont);
        Component comp = (Component) formDesigner.getComponent(metacomp);

        int resizable = laySup.getResizableDirections(
                                   cont, contDel,
                                   comp, metacont.getIndexOf(metacomp));
        if (resizable != 0)
            resizable &= getSelectionResizable(p, comp, 2);

        return resizable;
    }

    // Compute possible resizing directions according to mouse position on
    // component selection border.
    private int getSelectionResizable(Point p, Component comp, int borderWidth) {
        if (comp == null)
            return 0;

        Rectangle bounds = comp.getBounds();
        bounds.x = 0;
        bounds.y = 0;
        bounds = SwingUtilities.convertRectangle(comp, bounds, this);

        Rectangle r1 = new Rectangle(bounds);
        Rectangle r2 = new Rectangle(bounds);

        r1.grow(borderWidth, borderWidth);
        r2.grow(-3, -3);
        if (r2.width < 0)
            r2.width = 0;
        if (r2.height < 0)
            r2.height = 0;

        int resizable = 0;
        if (r1.contains(p)) {
            if (p.y >= r2.y + r2.height)
                resizable |= LayoutSupportManager.RESIZE_DOWN;
            else if (p.y < r2.y)
                resizable |= LayoutSupportManager.RESIZE_UP;
            if (p.x >= r2.x + r2.width)
                resizable |= LayoutSupportManager.RESIZE_RIGHT;
            else if (p.x < r2.x)
                resizable |= LayoutSupportManager.RESIZE_LEFT;
        }

        return resizable;
    }

    private void setResizingCursor(int resizeType) {
        Cursor cursor = null;
        if ((resizeType & LayoutSupportManager.RESIZE_UP) != 0) {
            if ((resizeType & LayoutSupportManager.RESIZE_LEFT) != 0)
                cursor = Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR);
            else if ((resizeType & LayoutSupportManager.RESIZE_RIGHT) != 0)
                cursor = Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR);
            else
                cursor = Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
        }
        else if ((resizeType & LayoutSupportManager.RESIZE_DOWN) != 0) {
            if ((resizeType & LayoutSupportManager.RESIZE_LEFT) != 0)
                cursor = Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR);
            else if ((resizeType & LayoutSupportManager.RESIZE_RIGHT) != 0)
                cursor = Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR);
            else
                cursor = Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
        }
        else if ((resizeType & LayoutSupportManager.RESIZE_LEFT) != 0)
            cursor = Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR);
        else if ((resizeType & LayoutSupportManager.RESIZE_RIGHT) != 0)
            cursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);

        if (cursor == null)
            cursor = Cursor.getDefaultCursor();

        setCursor(cursor);
    }

    private void setUserDesignerSize() {
        NotifyDescriptor.InputLine input = new NotifyDescriptor.InputLine(
            FormUtils.getBundleString("CTL_SetDesignerSize_Label"), // NOI18N
            FormUtils.getBundleString("CTL_SetDesignerSize_Title")); // NOI18N
        Dimension size = formDesigner.getComponentLayer().getDesignerSize();
        input.setInputText(Integer.toString(size.width) + ", " // NOI18N
                           + Integer.toString(size.height));

        if (DialogDisplayer.getDefault().notify(input) == NotifyDescriptor.OK_OPTION) {
            String txt = input.getInputText();
            int i = txt.indexOf(',');
            if (i > 0) {
                int n = txt.length();
                try {
                    int w = Integer.parseInt(txt.substring(0, i));
                    while (++i < n && txt.charAt(i) == ' ');
                    int h = Integer.parseInt(txt.substring(i, n));
                    if (w >= 0 && h >= 0) {
                        size = new Dimension(w ,h);
                        formDesigner.setStoredDesignerSize(size);
                        // update must be done immediately because of a weird
                        // mouse move event occurring after closing the input
                        // dialog but before updating the designer through
                        // synthetic property change processing
                        formDesigner.getComponentLayer().updateDesignerSize(size);
                        setToolTipText(null);
                        setCursor(Cursor.getDefaultCursor());
                    }
                }
                catch (NumberFormatException ex) {} // silently ignore, do nothing
            }
        }
    }

    private LayoutConstraints getConstraintsAtPoint(RADComponent metacomp,
                                                    Point point)
    {
        if (!(metacomp instanceof RADVisualComponent))
            return null;

        RADVisualContainer metacont = metacomp instanceof RADVisualContainer ?
            (RADVisualContainer) metacomp :
            (RADVisualContainer) metacomp.getParentComponent();
        if (metacont == null)
            return null;

        Container cont = (Container) formDesigner.getComponent(metacont);
        Container contDel = metacont.getContainerDelegate(cont);
        Point p = SwingUtilities.convertPoint(this, point, contDel);
        return metacont.getLayoutSupport().getNewConstraints(cont, contDel,
                                                             null, -1,
                                                             p, null);
    }

    private void showAddHint(RADComponent metacomp, Point p, PaletteItem item) {
        if ((!(metacomp instanceof RADVisualComponent) && metacomp != null)
            || item == null)
        {
            StatusDisplayer.getDefault().setStatusText(""); // NOI18N
            return;
        }

        if (metacomp == null) {
            setStatusText("FMT_MSG_AddToOthers", // NOI18N
                          new Object[] { item.getNode().getDisplayName() });
            return;
        }

        String displayName = item.getNode().getDisplayName();

        RADVisualContainer metacont = metacomp instanceof RADVisualContainer ?
            (RADVisualContainer) metacomp :
            (RADVisualContainer) metacomp.getParentComponent();

        if (item.isLayout()) {
            if (metacont != null) {
                if (!metacont.getLayoutSupport().isDedicated())
                    setStatusText("FMT_MSG_SetLayout", // NOI18N
                                  new Object[] { displayName,
                                                 metacont.getName() });
                else
                    setStatusText("FMT_MSG_CannotSetLayout", // NOI18N
                                  new Object[] { metacont.getName() });
            }
            else
                setStatusText("FMT_MSG_CannotSetLayout", // NOI18N
                              new Object[] { metacomp.getName() });
        }
        else if (item.isBorder()) {
            if (JComponent.class.isAssignableFrom(metacomp.getBeanClass()))
                setStatusText("FMT_MSG_SetBorder", // NOI18N
                              new Object[] { displayName, metacomp.getName() });
            else
                setStatusText("FMT_MSG_CannotSetBorder", // NOI18N
                              new Object[] { metacomp.getName() });
        }
        else if (metacont != null
                 && ((item.isMenu()
                        && metacont.getContainerMenu() == null
                        && metacont.canHaveMenu(item.getComponentClass()))
                     || (item.isVisual() && !item.isMenu())))
        {
            setStatusText("FMT_MSG_AddComponent", // NOI18N
                          new Object[] { displayName, metacont.getName() });
        }
        else {
            setStatusText("FMT_MSG_AddToOthers", // NOI18N
                          new Object[] { displayName });
        }
    }

    private static void setStatusText(String formatId, Object[] args) {
        StatusDisplayer.getDefault().setStatusText(
            FormUtils.getFormattedBundleString(formatId, args));
    }
    
    boolean mouseOnVisual(Point p) {
        Rectangle r = formDesigner.getComponentLayer().getDesignerOuterBounds();
        return r.contains(p);
    }

    // ---------

    private class HandleLayerMouseListener implements MouseListener
    {
        public void mouseClicked(MouseEvent e) {
            if (SwingUtilities.isRightMouseButton(e) && !anyDragger())
                if (!draggingCanceled)
                    showContextMenu(e.getPoint());
                else
                    draggingCanceled = false;

            e.consume();
        }

        public void mouseReleased(MouseEvent e) {
            if (!HandleLayer.this.isVisible())
                return;

            if (SwingUtilities.isLeftMouseButton(e)) {
                if (formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT
                    && !endDragging(e.getPoint()))
                {
                    if (draggingCanceled) {
                        draggingCanceled = false;
                    }
                    else if ((resizeType & DESIGNER_RESIZING) != 0
                             && e.getClickCount() == 2
                             && !e.isShiftDown()
                             && !e.isControlDown()
                             && !e.isAltDown())
                    {   // doubleclick on designer's resizing border
                        setUserDesignerSize();
                    }
                    else if (prevLeftMousePoint != null
                             && e.getClickCount() == 1
                             && prevLeftMousePoint.distance(e.getPoint()) <= 2
                             && !e.isShiftDown()
                             && !e.isControlDown()
                             && !e.isAltDown())
                    {   // second click on the same place in a component
                        formDesigner.startInPlaceEditing(
                            getMetaComponentAt(e.getPoint(), COMP_SELECTED));
                    }
                    else if (e.getClickCount() == 1
                             && !e.isAltDown()
                             && !e.isControlDown()
                             && e.isShiftDown())
                    {   // Shift + mouse release - interval selection
                        selectComponent(e);
                    }
                }

                prevLeftMousePoint = lastLeftMousePoint;
                lastLeftMousePoint = null;
            }

            e.consume();
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
            StatusDisplayer.getDefault().setStatusText(""); // NOI18N
        }

        public void mousePressed(MouseEvent e) {
            formDesigner.componentActivated();
            if (!HandleLayer.this.isVisible())
                return;

            if (SwingUtilities.isRightMouseButton(e)) {
                if (!anyDragger()) {
                    if (!mouseOnVisual(e.getPoint()))
                        selectOtherComponentsNode();
                    else {
                        RADComponent hitMetaComp =
                            getMetaComponentAt(e.getPoint(), COMP_SELECTED);
                        if (hitMetaComp != null
                            && !formDesigner.isComponentSelected(hitMetaComp))
                        {
                            formDesigner.setSelectedComponent(hitMetaComp);
                        }
                    }
                }
                else endDragging(null);

                e.consume();
            }
            else if (SwingUtilities.isLeftMouseButton(e)) {
                lastLeftMousePoint = e.getPoint();

                boolean modifier = e.isControlDown() || e.isAltDown() || e.isShiftDown();

                if (formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT) {
                    checkResizing(e);

                    if (!e.isShiftDown() || e.isAltDown() || e.isControlDown()) {
                        // mouse not pressed with Shift only (reserved for
                        // interval or area selection, applied on mouse release
                        // or mouse dragged)
                        if (designerResizer == null && !modifier
                            && (resizeType & DESIGNER_RESIZING) != 0)
                        {   // start designer resizing
                            if (e.getClickCount() != 2)
                                designerResizer = new DesignerResizer();
                        }
                        else if (!mouseOnVisual(lastLeftMousePoint)) {
                            if (resizeType == 0)
                                selectOtherComponentsNode();
                        }
                        else if (resizeType == 0
                                 && (e.getClickCount() != 2
                                     || !processDoubleClick(e)))
                        {   // no resizing, no doubleclick - select component
                            RADComponent hitMetaComp = selectComponent(e);
                            if (hitMetaComp != null && !modifier) // plain single click
                                processMouseClickInLayoutSupport(hitMetaComp, e);
                        }
                    }
                    draggingCanceled = false;
                }
                else if (!viewOnly) {
                    if (formDesigner.getDesignerMode() == FormDesigner.MODE_CONNECT) {
                        selectComponent(e);
                    }
                    else if (formDesigner.getDesignerMode() == FormDesigner.MODE_ADD) {
                        RADComponent hitMetaComp = getMetaComponentAt(
                            lastLeftMousePoint,
                            e.isAltDown() ? COMP_SELECTED : COMP_DEEPEST);

                        PaletteItem item = CPManager.getDefault().getSelectedItem();
                        if (item != null) {
                            Object constraints;

                            if (!item.isMenu() && item.isVisual()) {
                                constraints = getConstraintsAtPoint(
                                                hitMetaComp, lastLeftMousePoint);
                            }
                            else constraints = null;

                            if (!mouseOnVisual(lastLeftMousePoint)) {
                                formDesigner.getModel().getComponentCreator()
                                    .createComponent(item.getComponentClassSource(),
                                                     null, null);
                            }
                            else {
                                formDesigner.getModel().getComponentCreator()
                                    .createComponent(item.getComponentClassSource(),
                                                     hitMetaComp,
                                                     constraints);
                            }
                        }

                        if (!e.isShiftDown()) {
                            formDesigner.toggleSelectionMode();
                            draggingCanceled = true;
                        }
                    }
                }
                e.consume();
            }
        }
    }

    // ---------

    private class HandleLayerMouseMotionListener implements MouseMotionListener
    {
        public void mouseDragged(MouseEvent e) {
            Point p = e.getPoint();

            if (designerResizer != null) {
                designerResizer.drag(e.getPoint());
            }
            else if (formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT
                     && !anyDragger()
                     && !draggingCanceled)
            {
                if (!viewOnly
                     && !e.isControlDown() && (!e.isShiftDown() || e.isAltDown())
                     && lastLeftMousePoint != null
                     && (resizeType != 0 || lastLeftMousePoint.distance(p) > 8))
                {   // start components dragging
                    componentDragger = createComponentDragger(
                                         lastLeftMousePoint, e.getModifiers());
                }
                else if (formDesigner.getTopDesignComponent()
                                                instanceof RADVisualContainer
                         && !e.isAltDown() && !e.isControlDown()
                         && e.isShiftDown()
                         && lastLeftMousePoint != null
                         && lastLeftMousePoint.distance(p) > 4)
                {   // start selection dragging
                    selectionDragger = new SelectionDragger(lastLeftMousePoint);
                }
            }

            if (componentDragger != null) {
                componentDragger.drag(p);
                repaint();
            }
            if (selectionDragger != null) {
                selectionDragger.drag(p);
                repaint();
            }

            e.consume();
        }

        public void mouseMoved(MouseEvent e) {
            if (formDesigner.getDesignerMode() == FormDesigner.MODE_ADD) {
                RADComponent hitMetaComp =
                    getMetaComponentAt(e.getPoint(),
                                       e.isControlDown() || e.isAltDown() ?
                                           COMP_SELECTED : COMP_DEEPEST);
                showAddHint(hitMetaComp,
                            e.getPoint(),
                            CPManager.getDefault().getSelectedItem());
            }
            else if (formDesigner.getDesignerMode() == FormDesigner.MODE_SELECT)
                checkResizing(e);
        }
    }

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

    private class DesignerResizer {
        boolean dragged = false;

        public void drag(Point p) {
            Dimension size = computeDesignerSize(p);
            formDesigner.getComponentLayer().updateDesignerSize(size);
            if (!size.equals(formDesigner.getStoredDesignerSize()))
                dragged = true;
        }

        public void drop(Point p) {
            if (dragged) {
                Dimension size = computeDesignerSize(p);
                formDesigner.setStoredDesignerSize(size);
                // designer size in ComponentLayer will be updated
                // automatically through synthetic property change processing
            }
        }

        private Dimension computeDesignerSize(Point p) {
            Rectangle r =
                formDesigner.getComponentLayer().getDesignerInnerBounds();
            int w = r.width;
            int h = r.height;

            if ((resizeType & LayoutSupportManager.RESIZE_DOWN) != 0) {
                h = p.y - r.y;
                if (h < 0)
                    h = 0;
            }
            if ((resizeType & LayoutSupportManager.RESIZE_RIGHT) != 0) {
                w = p.x - r.x;
                if (w < 0)
                    w = 0;
            }

            return new Dimension(w, h);
        }
    }

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

    private class SelectionDragger {
        private Point startPoint;
        private Point lastPoint;

        public SelectionDragger(Point startPoint) {
            this.startPoint = startPoint;
        }

        public void paintDragFeedback(Graphics g) {
            if (startPoint != null && lastPoint != null) {
                Rectangle r = getRectangle();
                g.drawRect(r.x, r.y, r.width, r.height);
            }
        }

        public void drag(Point p) {
            lastPoint = p;
        }

        public void drop(Point endPoint) {
            if (startPoint != null && endPoint != null) {
                lastPoint = endPoint;
                ArrayList toSelect = new ArrayList();
                collectSelectedComponents(
                    getRectangle(),
                    formDesigner.getComponentLayer().getComponentContainer(),
                    toSelect);

                RADComponent[] selected = new RADComponent[toSelect.size()];
                toSelect.toArray(selected);
                formDesigner.setSelectedComponents(selected);
            }
        }

        private Rectangle getRectangle() {
            int x = startPoint.x <= lastPoint.x ? startPoint.x : lastPoint.x;
            int y = startPoint.y <= lastPoint.y ? startPoint.y : lastPoint.y;
            int w = lastPoint.x - startPoint.x;
            if (w < 0)
                w = -w;
            int h = lastPoint.y - startPoint.y;
            if (h < 0)
                h = -h;

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

        private boolean collectSelectedComponents(Rectangle selRect,
                                                  Container cont,
                                                  java.util.List toSelect)
        {
            ArrayList subContainers = new ArrayList();

            Component[] comps = cont.getComponents();
            for (int i=0; i < comps.length; i++) {
                Component comp = comps[i];
                Rectangle bounds = SwingUtilities.convertRectangle(
                                           cont,
                                           comps[i].getBounds(),
                                           HandleLayer.this);
                boolean intersects = selRect.intersects(bounds);

                RADComponent metacomp = formDesigner.getMetaComponent(comp);
                if (metacomp instanceof RADComponent) {
                    if (intersects)
                        toSelect.add(metacomp);
                    if (!(metacomp instanceof ComponentContainer))
                        continue;
                }

                if (intersects && comp instanceof Container)
                    subContainers.add(comp);
            }

            if (toSelect.size() > 1
                    || (toSelect.size() == 1 && subContainers.size() == 0))
                return true;

            Object theOnlyOne = toSelect.size() == 1 ? toSelect.get(0) : null;

            for (int i=0; i < subContainers.size(); i++) {
                toSelect.clear();
                if (collectSelectedComponents(selRect,
                                              (Container)subContainers.get(i),
                                              toSelect))
                    return true;
            }

            if (theOnlyOne != null) {
                toSelect.add(theOnlyOne);
                return true;
            }
            
            return false;
        }
    }
}
... 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.