Package org.eclipse.jst.pagedesigner.editpolicies

Source Code of org.eclipse.jst.pagedesigner.editpolicies.ElementResizableEditPolicy

/*******************************************************************************
* Copyright (c) 2006 Sybase, Inc. and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Sybase, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.pagedesigner.editpolicies;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.Assert;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.SharedCursors;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.ResizableEditPolicy;
import org.eclipse.gef.handles.NonResizableHandleKit;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.LocationRequest;
import org.eclipse.gef.requests.SelectionRequest;
import org.eclipse.gef.tools.SelectEditPartTracker;
import org.eclipse.jst.pagedesigner.commands.single.ChangeStyleCommand;
import org.eclipse.jst.pagedesigner.css2.ICSSStyle;
import org.eclipse.jst.pagedesigner.css2.layout.BlockBox;
import org.eclipse.jst.pagedesigner.css2.layout.CSSFigure;
import org.eclipse.jst.pagedesigner.dom.EditModelQuery;
import org.eclipse.jst.pagedesigner.parts.ElementEditPart;
import org.eclipse.jst.pagedesigner.parts.NodeEditPart;
import org.eclipse.jst.pagedesigner.requests.LocationModifierRequest;
import org.eclipse.jst.pagedesigner.tools.ObjectModeDragTracker;
import org.eclipse.jst.pagedesigner.tools.RangeDragTracker;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMElement;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* @author mengbo
* @version 1.5
*/
public class ElementResizableEditPolicy extends ResizableEditPolicy implements IEnhancedSelectionEditPolicy
{
  private static final Insets INSETS_1 = new Insets(1, 1, 1, 1);

  private static final int THRESHHOLD = 3;
   
    // the number of pixels to offset the top left of tooltop feedback
    // below the current mouse cursor location
    private static final int TOOLTIP_VERTICAL_OFFSET = 25;

  private static final Insets INSETS_CONST = new Insets(THRESHHOLD,
      THRESHHOLD, THRESHHOLD, THRESHHOLD);

  private boolean _showLabelFeedback = true;

  private IFigure[] _hoverFeedbackFigure;
   
    //private NonVisualChildDecorator   _selectionDecoratorNorthWest; // = null;
    private MouseSelectableChildDecorator   _nonVisualChildDecorator; // = null;
   
  private final static Color HOVER_FEEDBACK_COLOR = ColorConstants.blue;

  public void deactivate()
    {
        super.deactivate();
        if (_nonVisualChildDecorator != null)
        {
            _nonVisualChildDecorator.dispose();
            _nonVisualChildDecorator = null;
        }
    }

    /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.editpolicies.AbstractEditPolicy#showTargetFeedback(org.eclipse.gef.Request)
   */
  public void showTargetFeedback(Request request) {
    if (RequestConstants.REQ_SELECTION_HOVER.equals(request.getType())) {
      if (_hoverFeedbackFigure != null) {
        for (int i = 0; i < _hoverFeedbackFigure.length; i++) {
          removeFeedback(_hoverFeedbackFigure[i]);
        }
        _hoverFeedbackFigure = null;
            }
           
            // <gripe>this is what I hate about GEF, if it's a location dependent
            // request why aren't we guaranteed a LocationRequest?!
            // even GEF interal code protects casts by checking getType()
            // rather than an instanceof!</gripe>
            Assert.isTrue(request instanceof LocationRequest);
            // don't show tooltip if drag is active
            _showLabelFeedback = !((NodeEditPart)getHost()).isDragActive();
      _hoverFeedbackFigure = showHoverFeedback((LocationRequest)request);
    } else {
      super.showTargetFeedback(request);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.editpolicies.AbstractEditPolicy#eraseTargetFeedback(org.eclipse.gef.Request)
   */
  public void eraseTargetFeedback(Request request) {
    if (RequestConstants.REQ_SELECTION_HOVER.equals(request.getType())) {
      if (_hoverFeedbackFigure != null) {
        for (int i = 0; i < _hoverFeedbackFigure.length; i++) {
          removeFeedback(_hoverFeedbackFigure[i]);
        }
        _hoverFeedbackFigure = null;
                getNonVisualChildDecorator().updateState(MouseSelectableChildDecorator.EVENT_HOST_HOVER_LOST);
      }
    } else {
      super.eraseTargetFeedback(request);
    }
  }

  /**
   * @param request
   */
  private IFigure[] showHoverFeedback(LocationRequest request) {
    if (!shouldUseObjectMode(request) && !isStyleTags(getHost())) {
      return null;
    }

        final IFigure figure = this.getHostFigure();
    Rectangle[] rects;
    if (figure instanceof CSSFigure) {
      rects = ((CSSFigure) figure).getFragmentsBounds();
    } else {
      rects = new Rectangle[] { figure.getBounds() };
    }
        int figureSize = rects.length;
       
        if (_showLabelFeedback)
        {
            figureSize++;
        }
       
    IFigure[] figures = new IFigure[figureSize];
    for (int i = 0; i < rects.length; i++) {
      RectangleFigure fig = new RectangleFigure();
      fig.setFill(false);
      fig.setOutline(true);
      fig.setLineWidth(1);
      fig.setForegroundColor(HOVER_FEEDBACK_COLOR);
      addFeedback(fig);

      Rectangle r = rects[i].getCopy();
      figure.translateToAbsolute(r);
      fig.translateToRelative(r);
      fig.setBounds(r);

      figures[i] = fig;
    }
      
    if (_showLabelFeedback)
        {
            getNonVisualChildDecorator().updateState(MouseSelectableChildDecorator.EVENT_HOST_HOVER_RECEIVED);
           
      BasicLabelToolTip label = new BasicLabelToolTip(getTooltipText());
      addFeedback(label);

            // use mouse cursor plus an offset so the tooltip doesn't
            // appear z-ordered below the mouse cursor
            AbsolutePointLocator locator = AbsolutePointLocator.getInstance();
            locator.setReferencePoint(request.getLocation(), 0, TOOLTIP_VERTICAL_OFFSET);
            //  to avoid enlargemeent of the feedback layer
            locator.setIntersectFigure(getFeedbackLayer());
            locator.relocate(label);
      figures[rects.length] = label;
    }
    return figures;
  }

  private String getTooltipText() {
    Element element = (Element) this.getHost().getModel();
    StringBuffer text = new StringBuffer(element.getTagName());
    return text.toString();
  }

  private boolean isStyleTags(EditPart part) {
    if (part != null && part.getModel() instanceof Node) {
      return EditModelQuery.HTML_STYLE_NODES.contains(((Node) part
          .getModel()).getNodeName());
    }
        return false;
  }
    private MouseSelectableChildDecorator getNonVisualChildDecorator()
    {
        if  (_nonVisualChildDecorator == null)
        {
            _nonVisualChildDecorator =
                new MouseSelectableChildDecorator((GraphicalEditPart)getHost()
                        , PositionConstants.NORTH_EAST
                        , getLayer(LayerConstants.FEEDBACK_LAYER)
                        , getLayer(LayerConstants.HANDLE_LAYER));
        }
        return _nonVisualChildDecorator;
    }

  /**
   * @param request
   * @return true if we should be using object mode for this request
   */
  public boolean shouldUseObjectMode(Request request) {
    ElementEditPart part = (ElementEditPart) this.getHost();
    if (isStyleTags(part)) {
      return false;
    }
    if (part.isWidget()
        || (!part.canHaveDirectTextChild() && !part
            .haveNonWhitespaceTextChild())) {
      return true;
    }
    if (request instanceof SelectionRequest
        && ((SelectionRequest) request).isControlKeyPressed()) {
      return true;
    }
    if (request instanceof LocationModifierRequest
        && ((LocationModifierRequest) request).isControlKeyPressed()) {
      return true;
    }

    // for other elements
    if (request instanceof LocationRequest) {
      Point location = ((LocationRequest) request).getLocation()
          .getCopy();
      part.getFigure().translateToRelative(location);
      return shouldUseObjectMode(location);
    }
        return false; // should not happen
  }

  /**
   * @param location
   * @return
   */
  private boolean shouldUseObjectMode(Point location) {
    // when the location is close to the border/padding of the element, then
    // we think it is default to
    // object mode selection.
    CSSFigure figure = (CSSFigure) this.getHostFigure();
    if (figure.getFragmentsBounds().length != 1) {
      return false;
    }
    Rectangle bounds = figure.getBounds().getCopy();
    Insets insets = figure.getInsets();
    bounds.crop(insets);
    if (insets.top > THRESHHOLD && insets.left > THRESHHOLD
        && insets.right > THRESHHOLD && insets.bottom > THRESHHOLD) {
      return !bounds.contains(location);
    }

    // since the figure insets could be 0, so we expand it a little, thus
    // even the point is
    // a little inside the content area, we still think it is selection the
    // object.
    if (bounds.height < 3 * THRESHHOLD || bounds.width < 3 * THRESHHOLD) {
      bounds.crop(INSETS_1);
    } else {
      bounds.crop(INSETS_CONST);
    }
    return !bounds.contains(location);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.editpolicies.ResizableEditPolicy#createSelectionHandles()
   */
  protected List createSelectionHandles() {
    // we have three different kinds of handles.
    // 1. Those element that is resizable.
    // 2. Those element that is rectangle but not resizable.
    // 3. Those element that is not rectangle (fragments)

    IFigure figure = this.getHostFigure();
    if (figure instanceof CSSFigure && getHost() instanceof ElementEditPart) {
      CSSFigure cssfigure = (CSSFigure) figure;
      List fragments = cssfigure.getFragmentsForRead();

      // XXX: only one fragment and is blockbox, then we think it is
      // resizable by figure
      // should move this test to somewhere else.
      if (fragments != null && fragments.size() == 1
          && fragments.get(0) instanceof BlockBox) {
        if (((ElementEditPart) getHost()).isResizable()) {
          // super is Resizable policy, will create a resize handles.
          return super.createSelectionHandles();
        }
                return createNonResizeHandles();
      }
            return createFragmentsHandles();
    }
        // second case
        return createNonResizeHandles();
  }

  /**
   * @return
   */
  private List createFragmentsHandles() {
    List list = new ArrayList();
    list.add(new FragmentHandle((GraphicalEditPart) getHost()));
    return list;
  }

  /**
   * @return
   */
  private List createNonResizeHandles() {
    // following code copied from NonResizableEditPolicy
    List list = new ArrayList();
    if (isDragAllowed()) {
      NonResizableHandleKit.addHandles((GraphicalEditPart) getHost(),
          list);
    } else {
      NonResizableHandleKit.addHandles((GraphicalEditPart) getHost(),
          list, new SelectEditPartTracker(getHost()),
          SharedCursors.ARROW);
    }

    return list;
  }


    protected void hideSelection() {
        super.hideSelection();
        // handle removing the menu bar handle separately because it will decide
        // when to remove itself (not removeSelectionHandles)
        getNonVisualChildDecorator().updateState(MouseSelectableChildDecorator.EVENT_HOST_SELECTION_LOST);

    }

    protected void showSelection() {
        super.showSelection();
        // handle adding the menu bar handle separately because it will decide
        // when to remove itself (not removeSelectionHandles
        getNonVisualChildDecorator().updateState(MouseSelectableChildDecorator.EVENT_HOST_SELECTION_RECEIVED);
    }

    /**
   * child class could override this method.
   *
     * @param element
   * @param width
   * @param height
   * @return the resize command or null  if none
   */
  protected Command getResizeCommand(IDOMElement element, int width,
      int height) {
    Map map = new HashMap();
    if (width > 0) {
      map.put("width", width + "px"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    if (height > 0) {
      map.put("height", height + "px"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    if (!map.isEmpty()) {
            return new ChangeStyleCommand(element, map);
    }
        return null;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.editpolicies.ResizableEditPolicy#getResizeCommand(org.eclipse.gef.requests.ChangeBoundsRequest)
   */
  protected Command getResizeCommand(ChangeBoundsRequest request) {
    ElementEditPart part = (ElementEditPart) this.getHost();

    Rectangle rect = part.getFigure().getBounds();
    rect = request.getTransformedRectangle(rect);
    int width = rect.width;
    int height = rect.height;

    // since the user dragged rectangle included border/padding of the
    // element. And if the element's
    // width/height style setting don't include border padding, then we need
    // to set the element's width/height
    // style property a little smaller.
    if (part.getFigure() instanceof CSSFigure) {
      CSSFigure cssfigure = (CSSFigure) part.getFigure();
      ICSSStyle style = cssfigure.getCSSStyle();
      if (style != null && !style.isSizeIncludeBorderPadding()) {
        width -= (style.getBorderInsets().getWidth() + style
            .getPaddingInsets().getWidth());
        height -= (style.getBorderInsets().getHeight() + style
            .getPaddingInsets().getHeight());
      }
    }

    //make sure to only change the dimensions for the direction of the resize request.
    int resizeDirection = request.getResizeDirection();
    switch (resizeDirection) {
      case PositionConstants.EAST:
      case PositionConstants.WEST:
        //resizing, only the width, so set the height to -1;
        height = -1;
        break;
      case PositionConstants.NORTH:
      case PositionConstants.SOUTH:
        //resizing only the height, so set the width to -1
        width = -1;
        break;
      default:
        //all others are changing both directions...
    }
    return getResizeCommand((IDOMElement) part.getIDOMNode(), width, height);
  }

  /**
   * Shows or updates feedback for a change bounds request.
   *
   * @param request
   *            the request
   */
  protected void showChangeBoundsFeedback(ChangeBoundsRequest request) {
    IFigure feedback = getDragSourceFeedbackFigure();

    PrecisionRectangle rect = new PrecisionRectangle(
        getInitialFeedbackBounds().getCopy());
    getHostFigure().translateToAbsolute(rect);
    rect.translate(request.getMoveDelta());
    rect.resize(request.getSizeDelta());

    // to avoid enlarge feedback pane.
    // when draging a editpart inside designer to move/copy it, we do not
    // want to
    // enlarge the canvas, since that may resulting in relayout.
    rect = (PrecisionRectangle) rect.intersect(getFeedbackLayer()
        .getBounds());

    feedback.translateToRelative(rect);
    feedback.setBounds(rect);
  }

    public Cursor getSelectionToolCursor(Point mouseLocation) {
        // by default return null to indicate system default. 
        // sub-classes should override to customize
        return null;
    }

    /**
     * by default, return null
     * sub-classes should override to customize
     * @param request
     * @return the selectin tracker
     */
    protected DragTracker getSelectionTracker(LocationRequest request)
    {
        return null;
    }
   
    public DragTracker getSelectionDragTracker(LocationRequest request)
    {
        if (org.eclipse.jst.pagedesigner.requests.PageDesignerRequestConstants.REQ_SELECTION_TRACKER.equals(request.getType())){
            return getSelectionTracker(request);
        }
       
        // be default don't specify a selection drag tracker
        // sub-classes should override to customize
        if (shouldUseObjectMode(request)) {
            return new ObjectModeDragTracker(getHost());
        }
        return new RangeDragTracker(getHost());

    }
}
TOP

Related Classes of org.eclipse.jst.pagedesigner.editpolicies.ElementResizableEditPolicy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.