Package com.google.gdt.eclipse.designer.model.widgets.panels

Source Code of com.google.gdt.eclipse.designer.model.widgets.panels.LayoutPanelInfo

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package com.google.gdt.eclipse.designer.model.widgets.panels;

import com.google.common.collect.Maps;
import com.google.gdt.eclipse.designer.model.widgets.WidgetInfo;

import org.eclipse.wb.core.model.ObjectInfo;
import org.eclipse.wb.core.model.broadcast.ObjectEventListener;
import org.eclipse.wb.core.model.broadcast.ObjectInfoAllProperties;
import org.eclipse.wb.core.model.broadcast.ObjectInfoDeactivePropertyEditor;
import org.eclipse.wb.draw2d.geometry.Dimension;
import org.eclipse.wb.draw2d.geometry.Point;
import org.eclipse.wb.draw2d.geometry.Rectangle;
import org.eclipse.wb.internal.core.model.JavaInfoEvaluationHelper;
import org.eclipse.wb.internal.core.model.JavaInfoUtils;
import org.eclipse.wb.internal.core.model.creation.CreationSupport;
import org.eclipse.wb.internal.core.model.description.ComponentDescription;
import org.eclipse.wb.internal.core.model.property.ComplexProperty;
import org.eclipse.wb.internal.core.model.property.Property;
import org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
import org.eclipse.wb.internal.core.model.property.editor.DoublePropertyEditor;
import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
import org.eclipse.wb.internal.core.model.property.editor.StringComboPropertyEditor;
import org.eclipse.wb.internal.core.model.util.TemplateUtils;
import org.eclipse.wb.internal.core.utils.ast.AstEditor;
import org.eclipse.wb.internal.core.utils.ast.AstNodeUtils;
import org.eclipse.wb.internal.core.utils.ast.DomGenerics;
import org.eclipse.wb.internal.core.utils.ast.StatementTarget;
import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.execution.RunnableObjectEx;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Statement;

import org.apache.commons.lang.StringUtils;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
* Model for GWT <code>com.google.gwt.user.client.ui.LayoutPanel</code>.
*
* @author scheglov_ke
* @coverage gwt.model
*/
public class LayoutPanelInfo extends ComplexPanelInfo implements ILayoutPanelInfo<WidgetInfo> {
  private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("0.0",
      new DecimalFormatSymbols(Locale.ENGLISH));
  private final LayoutPanelAlignmentSupport<WidgetInfo> m_alignmentSupport;

  ////////////////////////////////////////////////////////////////////////////
  //
  // Constructor
  //
  ////////////////////////////////////////////////////////////////////////////
  public LayoutPanelInfo(AstEditor editor,
      ComponentDescription description,
      CreationSupport creationSupport) throws Exception {
    super(editor, description, creationSupport);
    m_alignmentSupport = new LayoutPanelAlignmentSupport<WidgetInfo>(this);
    addBroadcastListener(new ObjectEventListener() {
      @Override
      public void childRemoveBefore(ObjectInfo parent, ObjectInfo child) throws Exception {
        if (parent == LayoutPanelInfo.this && child instanceof WidgetInfo) {
          WidgetInfo widget = (WidgetInfo) child;
          for (MethodInvocation invocation : getMethodInvocations()) {
            if (isLocationInvocation(invocation, widget)) {
              getEditor().removeEnclosingStatement(invocation);
            }
          }
        }
      }

      private boolean isLocationInvocation(MethodInvocation invocation, WidgetInfo widget) {
        String signature = AstNodeUtils.getMethodSignature(invocation);
        if (signature.startsWith("setWidget")
            && signature.endsWith("(com.google.gwt.user.client.ui.Widget,"
                + "double,com.google.gwt.dom.client.Style.Unit,"
                + "double,com.google.gwt.dom.client.Style.Unit)")) {
          Expression widgetExpression = DomGenerics.arguments(invocation).get(0);
          return widget.isRepresentedBy(widgetExpression);
        }
        return false;
      }
    });
    addLocationProperties();
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Access
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the provider for managing "anchor".
   */
  public LayoutPanelAlignmentSupport<WidgetInfo> getAlignmentSupport() {
    return m_alignmentSupport;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Location properties
  //
  ////////////////////////////////////////////////////////////////////////////
  private void addLocationProperties() {
    addBroadcastListener(new ObjectInfoAllProperties() {
      public void invoke(ObjectInfo object, List<Property> properties) throws Exception {
        if (object instanceof WidgetInfo && object.getParent() == LayoutPanelInfo.this) {
          WidgetInfo widget = (WidgetInfo) object;
          addLocationProperties(properties, widget, true, "Anchor H");
          addLocationProperties(properties, widget, false, "Anchor V");
        }
      }
    });
  }

  private void addLocationProperties(List<Property> properties,
      WidgetInfo widget,
      boolean horizontal,
      String title) {
    MethodInvocation invocation = getLocationInvocation(widget, horizontal);
    if (invocation == null) {
      return;
    }
    String signature = AstNodeUtils.getMethodSignature(invocation);
    //
    ComplexProperty complexProperty;
    {
      @SuppressWarnings("unchecked")
      Map<String, ComplexProperty> complexProperties =
          (Map<String, ComplexProperty>) widget.getArbitraryValue(this);
      if (complexProperties == null) {
        complexProperties = Maps.newTreeMap();
        widget.putArbitraryValue(this, complexProperties);
      }
      complexProperty = complexProperties.get(title);
      if (complexProperty == null) {
        complexProperty = new ComplexProperty(title, "<properties>");
        complexProperty.setCategory(PropertyCategory.system(10));
        complexProperties.put(signature, complexProperty);
      }
      properties.add(complexProperty);
    }
    // update sub-properties
    String[] propertyTitles = getLocationPropertyTitles(signature);
    String title_1 = propertyTitles[0];
    String title_3 = propertyTitles[1];
    Property property_1 = new LocationValue_Property(title_1, invocation, 1);
    Property property_1u = new LocationUnit_Property(title_1 + " unit", invocation, 2, horizontal);
    Property property_3 = new LocationValue_Property(title_3, invocation, 3);
    Property property_3u = new LocationUnit_Property(title_3 + " unit", invocation, 4, horizontal);
    Property[] subProperties = new Property[]{property_1, property_1u, property_3, property_3u};
    complexProperty.setProperties(subProperties);
  }

  /**
   * Converts "setWidgetLeftRight()" into <code>["left", "right"]</code>.
   */
  private static String[] getLocationPropertyTitles(String signature) {
    String name = StringUtils.substringBefore(signature, "(");
    String elementsName = StringUtils.remove(name, "setWidget");
    String[] titles = StringUtils.splitByCharacterTypeCamelCase(elementsName);
    Assert.isTrue(titles.length == 2, signature);
    titles[0] = titles[0].toLowerCase();
    titles[1] = titles[1].toLowerCase();
    return titles;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Property: value
  //
  ////////////////////////////////////////////////////////////////////////////
  private final class LocationValue_Property extends Property {
    private final String m_title;
    private final int m_index;
    private final MethodInvocation m_invocation;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public LocationValue_Property(String title, MethodInvocation invocation, int index) {
      super(DoublePropertyEditor.INSTANCE);
      m_title = title;
      m_invocation = invocation;
      m_index = index;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Property
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public String getTitle() {
      return m_title;
    }

    @Override
    public boolean isModified() throws Exception {
      return true;
    }

    @Override
    public Object getValue() throws Exception {
      Expression expression = DomGenerics.arguments(m_invocation).get(m_index);
      return JavaInfoEvaluationHelper.getValue(expression);
    }

    @Override
    public void setValue(Object value) throws Exception {
      if (value instanceof Double) {
        final double pixels = ((Double) value).doubleValue();
        ExecutionUtils.run(LayoutPanelInfo.this, new RunnableEx() {
          public void run() throws Exception {
            setInvocationArgument(m_invocation, m_index, pixels);
          }
        });
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Property: unit
  //
  ////////////////////////////////////////////////////////////////////////////
  private static final String[] UNIT_NAMES =
      {"PX", "PCT", "EM", "EX", "PT", "PC", "IN", "CM", "MM"};
  private static final PropertyEditor UNIT_PROPERTY_EDITOR =
      new StringComboPropertyEditor(UNIT_NAMES);

  private final class LocationUnit_Property extends Property {
    private final String m_title;
    private final int m_index;
    private final MethodInvocation m_invocation;
    private final boolean m_horizontal;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public LocationUnit_Property(String title,
        MethodInvocation invocation,
        int index,
        boolean horizontal) {
      super(UNIT_PROPERTY_EDITOR);
      m_title = title;
      m_invocation = invocation;
      m_index = index;
      m_horizontal = horizontal;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Property
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public String getTitle() {
      return m_title;
    }

    @Override
    public boolean isModified() throws Exception {
      return true;
    }

    @Override
    public Object getValue() throws Exception {
      return getUnit(m_invocation, m_index).toString();
    }

    @Override
    public void setValue(final Object value) throws Exception {
      if (value instanceof String) {
        ExecutionUtils.run(LayoutPanelInfo.this, new RunnableEx() {
          public void run() throws Exception {
            changeInvocationUnit(m_invocation, m_index, value, m_horizontal);
          }
        });
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Hint
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the location hint in units for given location in pixels.
   */
  public String getLocationHint(final WidgetInfo widget, final int x, final int y) {
    return ExecutionUtils.runObjectIgnore(new RunnableObjectEx<String>() {
      public String runObject() throws Exception {
        return getLocationHint(x, widget, true) + " x " + getLocationHint(y, widget, false);
      }
    }, x + " x " + y);
  }

  private String getLocationHint(int pixels, WidgetInfo widget, boolean horizontal)
      throws Exception {
    MethodInvocation invocation = getLocationInvocation(widget, horizontal);
    // may be trailing
    if (isLocationTrailing(invocation)) {
      if (horizontal) {
        pixels = getBounds().width - (widget.getBounds().width + pixels);
      } else {
        pixels = getBounds().height - (widget.getBounds().height + pixels);
      }
    }
    // convert pixels to units
    Object unit = getLocationUnit(invocation);
    double units = pixels / getUnitSize(unit, !horizontal);
    return SIZE_FORMAT.format(units) + unit.toString().toLowerCase();
  }

  /**
   * @return <code>true</code> if {@link WidgetInfo} is attached to trailing size of panel.
   */
  public boolean getLocationHint_isTrailing(WidgetInfo widget, boolean horizontal) {
    MethodInvocation invocation = getLocationInvocation(widget, horizontal);
    return isLocationTrailing(invocation);
  }

  /**
   * @return <code>true</code> if {@link MethodInvocation} is attachment to trailing size of panel.
   */
  private boolean isLocationTrailing(MethodInvocation invocation) {
    if (invocation != null) {
      String name = invocation.getName().getIdentifier();
      return "setWidgetRightWidth".equals(name) || "setWidgetBottomHeight".equals(name);
    }
    return false;
  }

  private Object getLocationUnit(MethodInvocation invocation) throws Exception {
    if (invocation != null) {
      return getUnit(invocation, 2);
    }
    return getUnitByName("PX");
  }

  MethodInvocation getLocationInvocation(WidgetInfo widget, boolean horizontal) {
    MethodInvocation invocation;
    if (horizontal) {
      if ((invocation = getWidgetInvocation(widget, "setWidgetLeftWidth")) != null) {
        return invocation;
      }
      if ((invocation = getWidgetInvocation(widget, "setWidgetRightWidth")) != null) {
        return invocation;
      }
      if ((invocation = getWidgetInvocation(widget, "setWidgetLeftRight")) != null) {
        return invocation;
      }
    } else {
      if ((invocation = getWidgetInvocation(widget, "setWidgetTopHeight")) != null) {
        return invocation;
      }
      if ((invocation = getWidgetInvocation(widget, "setWidgetBottomHeight")) != null) {
        return invocation;
      }
      if ((invocation = getWidgetInvocation(widget, "setWidgetTopBottom")) != null) {
        return invocation;
      }
    }
    return null;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Bounds: location
  //
  ////////////////////////////////////////////////////////////////////////////
  public void command_LOCATION(WidgetInfo widget, Point location) throws Exception {
    command_LOCATION_Y(widget, location.y);
    command_LOCATION_X(widget, location.x);
  }

  private void command_LOCATION_X(WidgetInfo widget, int x) throws Exception {
    // LeftWidth
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetLeftWidth");
      if (invocation != null) {
        setInvocationArgument(invocation, 1, x, true);
        return;
      }
    }
    // RightWidth
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetRightWidth");
      if (invocation != null) {
        int right = getBounds().width - x - widget.getBounds().width;
        setInvocationArgument(invocation, 1, right, true);
        return;
      }
    }
    // LeftRight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetLeftRight");
      if (invocation != null) {
        int right = getBounds().width - x - widget.getBounds().width;
        setInvocationArgument(invocation, 1, x, true);
        setInvocationArgument(invocation, 3, right, true);
        return;
      }
    }
    // new, use LeftWidth
    {
      int defaultWidth = getDefaultSize(widget).width;
      String source =
          TemplateUtils.format(
              "{0}.setWidgetLeftWidth({1}, {2}, {3}, {4}, {3})",
              this,
              widget,
              SIZE_FORMAT.format(x),
              "com.google.gwt.dom.client.Style.Unit.PX",
              SIZE_FORMAT.format(defaultWidth));
      StatementTarget target = getNewConstraintsTarget(widget);
      Expression expression = widget.addExpressionStatement(target, source);
      addRelatedNodes(expression);
    }
  }

  private void command_LOCATION_Y(WidgetInfo widget, int y) throws Exception {
    // TopHeight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetTopHeight");
      if (invocation != null) {
        setInvocationArgument(invocation, 1, y, false);
        return;
      }
    }
    // BottomHeight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetBottomHeight");
      if (invocation != null) {
        int bottom = getBounds().height - y - widget.getBounds().height;
        setInvocationArgument(invocation, 1, bottom, false);
        return;
      }
    }
    // TopBottom
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetTopBottom");
      if (invocation != null) {
        int bottom = getBounds().height - y - widget.getBounds().height;
        setInvocationArgument(invocation, 1, y, false);
        setInvocationArgument(invocation, 3, bottom, false);
        return;
      }
    }
    // new, use TopHeight
    {
      int defaultHeight = getDefaultSize(widget).height;
      String source =
          TemplateUtils.format(
              "{0}.setWidgetTopHeight({1}, {2}, {3}, {4}, {3})",
              this,
              widget,
              SIZE_FORMAT.format(y),
              "com.google.gwt.dom.client.Style.Unit.PX",
              SIZE_FORMAT.format(defaultHeight));
      StatementTarget target = getNewConstraintsTarget(widget);
      Expression expression = widget.addExpressionStatement(target, source);
      addRelatedNodes(expression);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Bounds: size
  //
  ////////////////////////////////////////////////////////////////////////////
  public void command_SIZE(WidgetInfo widget,
      Dimension size,
      ResizeDirection hDirection,
      ResizeDirection vDirection) throws Exception {
    command_SIZE_Y(widget, size.height, vDirection);
    command_SIZE_X(widget, size.width, hDirection);
  }

  private void command_SIZE_X(WidgetInfo widget, int width, ResizeDirection direction)
      throws Exception {
    Rectangle bounds = widget.getBounds();
    // LeftWidth
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetLeftWidth");
      if (invocation != null) {
        if (direction == ResizeDirection.LEADING) {
          int oldLeft = bounds.left();
          int deltaWidth = width - bounds.width;
          int left = oldLeft - deltaWidth;
          setInvocationArgument(invocation, 1, left, true);
        }
        setInvocationArgument(invocation, 3, width, true);
        return;
      }
    }
    // RightWidth
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetRightWidth");
      if (invocation != null) {
        if (direction == ResizeDirection.TRAILING) {
          int oldRight = getBounds().width - bounds.right();
          int deltaWidth = width - bounds.width;
          int right = oldRight - deltaWidth;
          setInvocationArgument(invocation, 1, right, true);
        }
        setInvocationArgument(invocation, 3, width, true);
        return;
      }
    }
    // LeftRight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetLeftRight");
      if (invocation != null) {
        if (direction == ResizeDirection.LEADING) {
          int oldLeft = bounds.left();
          int deltaWidth = width - bounds.width;
          int left = oldLeft - deltaWidth;
          setInvocationArgument(invocation, 1, left, true);
        }
        if (direction == ResizeDirection.TRAILING) {
          int oldRight = getBounds().width - bounds.right();
          int deltaWidth = width - bounds.width;
          int right = oldRight - deltaWidth;
          setInvocationArgument(invocation, 3, right, true);
        }
        return;
      }
    }
    // new, use LeftWidth
    if (direction == ResizeDirection.TRAILING) {
      String source =
          TemplateUtils.format(
              "{0}.setWidgetLeftWidth({1}, {2}, {3}, {4}, {3})",
              this,
              widget,
              SIZE_FORMAT.format(0.0),
              "com.google.gwt.dom.client.Style.Unit.PX",
              SIZE_FORMAT.format(width));
      StatementTarget target = getNewConstraintsTarget(widget);
      Expression expression = widget.addExpressionStatement(target, source);
      addRelatedNodes(expression);
    }
  }

  private void command_SIZE_Y(WidgetInfo widget, int height, ResizeDirection direction)
      throws Exception {
    Rectangle bounds = widget.getBounds();
    // TopHeight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetTopHeight");
      if (invocation != null) {
        if (direction == ResizeDirection.LEADING) {
          int oldTop = bounds.top();
          int deltaHeight = height - bounds.height;
          int top = oldTop - deltaHeight;
          setInvocationArgument(invocation, 1, top, false);
        }
        setInvocationArgument(invocation, 3, height, false);
        return;
      }
    }
    // BottomHeight
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetBottomHeight");
      if (invocation != null) {
        if (direction == ResizeDirection.TRAILING) {
          int oldBottom = getBounds().height - bounds.bottom();
          int deltaHeight = height - bounds.height;
          int bottom = oldBottom - deltaHeight;
          setInvocationArgument(invocation, 1, bottom, false);
        }
        setInvocationArgument(invocation, 3, height, false);
        return;
      }
    }
    // TopBottom
    {
      MethodInvocation invocation = getWidgetInvocation(widget, "setWidgetTopBottom");
      if (invocation != null) {
        if (direction == ResizeDirection.LEADING) {
          int oldTop = bounds.top();
          int deltaHeight = height - bounds.height;
          int top = oldTop - deltaHeight;
          setInvocationArgument(invocation, 1, top, false);
        }
        if (direction == ResizeDirection.TRAILING) {
          int oldBottom = getBounds().height - bounds.bottom();
          int deltaHeight = height - bounds.height;
          int bottom = oldBottom - deltaHeight;
          setInvocationArgument(invocation, 3, bottom, false);
        }
        return;
      }
    }
    // new, use TopHeight
    if (direction == ResizeDirection.TRAILING) {
      String source =
          TemplateUtils.format(
              "{0}.setWidgetTopHeight({1}, {2}, {3}, {4}, {3})",
              this,
              widget,
              SIZE_FORMAT.format(0.0),
              "com.google.gwt.dom.client.Style.Unit.PX",
              SIZE_FORMAT.format(height));
      StatementTarget target = getNewConstraintsTarget(widget);
      Expression expression = widget.addExpressionStatement(target, source);
      addRelatedNodes(expression);
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Anchor
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the {@link Anchor} type for given {@link WidgetInfo}.
   */
  public Anchor getAnchor(WidgetInfo widget, boolean horizontal) {
    if (horizontal) {
      if (getWidgetInvocation(widget, "setWidgetLeftWidth") != null) {
        return Anchor.LEADING;
      }
      if (getWidgetInvocation(widget, "setWidgetRightWidth") != null) {
        return Anchor.TRAILING;
      }
      if (getWidgetInvocation(widget, "setWidgetLeftRight") != null) {
        return Anchor.BOTH;
      }
    } else {
      if (getWidgetInvocation(widget, "setWidgetTopHeight") != null) {
        return Anchor.LEADING;
      }
      if (getWidgetInvocation(widget, "setWidgetBottomHeight") != null) {
        return Anchor.TRAILING;
      }
      if (getWidgetInvocation(widget, "setWidgetTopBottom") != null) {
        return Anchor.BOTH;
      }
    }
    return Anchor.NONE;
  }

  /**
   * Sets anchor for given {@link WidgetInfo}.
   */
  public void command_ANCHOR(WidgetInfo widget, boolean horizontal, Anchor anchor) throws Exception {
    if (horizontal) {
      command_ANCHOR_horizontal(widget, anchor);
    } else {
      command_ANCHOR_vertical(widget, anchor);
    }
    getBroadcast(ObjectInfoDeactivePropertyEditor.class).invoke();
  }

  private void command_ANCHOR_horizontal(WidgetInfo widget, Anchor anchor) throws Exception {
    MethodInvocation invocation;
    Rectangle bounds = widget.getBounds();
    AstEditor editor = getEditor();
    if ((invocation = getWidgetInvocation(widget, "setWidgetLeftWidth")) != null) {
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.TRAILING) {
        int right = getBounds().width - bounds.right();
        editor.replaceInvocationName(invocation, "setWidgetRightWidth");
        setInvocationArgument(invocation, 1, right, true);
      }
      if (anchor == Anchor.BOTH) {
        int right = getBounds().width - bounds.right();
        editor.replaceInvocationName(invocation, "setWidgetLeftRight");
        setInvocationArgument(invocation, 3, right, true);
      }
      return;
    }
    if ((invocation = getWidgetInvocation(widget, "setWidgetRightWidth")) != null) {
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.LEADING) {
        int left = bounds.left();
        editor.replaceInvocationName(invocation, "setWidgetLeftWidth");
        setInvocationArgument(invocation, 1, left, true);
      }
      if (anchor == Anchor.BOTH) {
        editor.replaceInvocationName(invocation, "setWidgetLeftRight");
        {
          Expression rightExpression = DomGenerics.arguments(invocation).get(1);
          editor.replaceInvocationArgument(invocation, 3, editor.getSource(rightExpression));
        }
        setInvocationArgument(invocation, 1, bounds.left(), true);
      }
      return;
    }
    if ((invocation = getWidgetInvocation(widget, "setWidgetLeftRight")) != null) {
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.LEADING) {
        editor.replaceInvocationName(invocation, "setWidgetLeftWidth");
        // use same unit for left/width
        Object unit = getUnit(invocation, 2);
        setInvocationUnit(invocation, 4, unit);
        // set width
        setInvocationArgument(invocation, 3, bounds.width, true);
      }
      if (anchor == Anchor.TRAILING) {
        editor.replaceInvocationName(invocation, "setWidgetRightWidth");
        // use same unit for right/width
        Object unit = getUnit(invocation, 4);
        setInvocationUnit(invocation, 2, unit);
        // set right/width
        {
          Expression rightExpression = DomGenerics.arguments(invocation).get(3);
          editor.replaceInvocationArgument(invocation, 1, editor.getSource(rightExpression));
        }
        // set width
        setInvocationArgument(invocation, 3, bounds.width, true);
      }
      return;
    }
    // no anchor yet, generate LEADING and convert
    if (anchor != Anchor.NONE) {
      command_LOCATION_X(widget, bounds.left());
      command_SIZE_X(widget, bounds.width, ResizeDirection.TRAILING);
      if (anchor == Anchor.TRAILING) {
        command_ANCHOR_horizontal(widget, anchor);
      }
      if (anchor == Anchor.BOTH) {
        command_ANCHOR_horizontal(widget, anchor);
      }
    }
  }

  private void command_ANCHOR_vertical(WidgetInfo widget, Anchor anchor) throws Exception {
    MethodInvocation invocation;
    Rectangle bounds = widget.getBounds();
    AstEditor editor = getEditor();
    if ((invocation = getWidgetInvocation(widget, "setWidgetTopHeight")) != null) {
      int bottom = getBounds().height - bounds.bottom();
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.TRAILING) {
        editor.replaceInvocationName(invocation, "setWidgetBottomHeight");
        setInvocationArgument(invocation, 1, bottom, true);
      }
      if (anchor == Anchor.BOTH) {
        editor.replaceInvocationName(invocation, "setWidgetTopBottom");
        setInvocationArgument(invocation, 3, bottom, true);
      }
      return;
    }
    if ((invocation = getWidgetInvocation(widget, "setWidgetBottomHeight")) != null) {
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.LEADING) {
        editor.replaceInvocationName(invocation, "setWidgetTopHeight");
        setInvocationArgument(invocation, 1, bounds.top(), true);
      }
      if (anchor == Anchor.BOTH) {
        editor.replaceInvocationName(invocation, "setWidgetTopBottom");
        {
          Expression rightExpression = DomGenerics.arguments(invocation).get(1);
          editor.replaceInvocationArgument(invocation, 3, editor.getSource(rightExpression));
        }
        setInvocationArgument(invocation, 1, bounds.top(), true);
      }
      return;
    }
    if ((invocation = getWidgetInvocation(widget, "setWidgetTopBottom")) != null) {
      if (anchor == Anchor.NONE) {
        editor.removeEnclosingStatement(invocation);
      }
      if (anchor == Anchor.LEADING) {
        editor.replaceInvocationName(invocation, "setWidgetTopHeight");
        // use same unit for top/height
        Object unit = getUnit(invocation, 2);
        setInvocationUnit(invocation, 4, unit);
        // set height
        setInvocationArgument(invocation, 3, bounds.height, true);
      }
      if (anchor == Anchor.TRAILING) {
        editor.replaceInvocationName(invocation, "setWidgetBottomHeight");
        // use same unit for bottom/height
        Object unit = getUnit(invocation, 4);
        setInvocationUnit(invocation, 2, unit);
        // set bottom/height
        {
          Expression bottomExpression = DomGenerics.arguments(invocation).get(3);
          editor.replaceInvocationArgument(invocation, 1, editor.getSource(bottomExpression));
        }
        // set height
        setInvocationArgument(invocation, 3, bounds.height, true);
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Utils
  //
  ////////////////////////////////////////////////////////////////////////////
  private static StatementTarget getNewConstraintsTarget(WidgetInfo widget) {
    Statement associationStatement = widget.getAssociation().getStatement();
    return new StatementTarget(associationStatement, false);
  }

  private MethodInvocation getWidgetInvocation(WidgetInfo widget, String name) {
    List<MethodInvocation> invocations =
        getMethodInvocations(name
            + "(com.google.gwt.user.client.ui.Widget,"
            + "double,com.google.gwt.dom.client.Style.Unit,"
            + "double,com.google.gwt.dom.client.Style.Unit)");
    for (MethodInvocation invocation : invocations) {
      Expression widgetExpression = DomGenerics.arguments(invocation).get(0);
      if (widget.isRepresentedBy(widgetExpression)) {
        return invocation;
      }
    }
    return null;
  }

  /**
   * @return the <code>Unit</code> value of {@link MethodInvocation} argument.
   */
  private Object getUnit(MethodInvocation invocation, int index) throws Exception {
    Expression argument = DomGenerics.arguments(invocation).get(index);
    Object value = JavaInfoEvaluationHelper.getValue(argument);
    if (value != null) {
      return value;
    }
    return getUnitByName("PX");
  }

  /**
   * @return the <code>double</code> value of {@link MethodInvocation} argument.
   */
  private double getValue(MethodInvocation invocation, int index) throws Exception {
    Expression argument = DomGenerics.arguments(invocation).get(index);
    Object value = JavaInfoEvaluationHelper.getValue(argument);
    if (value instanceof Double) {
      return (Double) value;
    }
    return 0.0;
  }

  /**
   * @return the <code>Unit</code> object by its name.
   */
  private Object getUnitByName(String name) throws ClassNotFoundException {
    ClassLoader classLoader = JavaInfoUtils.getClassLoader(this);
    Class<?> classUnit = classLoader.loadClass("com.google.gwt.dom.client.Style$Unit");
    return ReflectionUtils.getFieldObject(classUnit, name);
  }

  /**
   * @return the size of "Unit" in pixels.
   */
  private double getUnitSize(Object unit, boolean horizontal) {
    Object layout = ReflectionUtils.getFieldObject(getObject(), "layout");
    return (Double) ReflectionUtils.invokeMethodEx(
        layout,
        "getUnitSize(com.google.gwt.dom.client.Style.Unit,boolean)",
        unit,
        !horizontal);
  }

  /**
   * Sets {@link MethodInvocation} argument is appropriate units, for given value in pixels.
   */
  private void setInvocationArgument(MethodInvocation invocation,
      int index,
      int pixels,
      boolean horizontal) throws Exception {
    Object unit = getUnit(invocation, index + 1);
    double units = pixels / getUnitSize(unit, horizontal);
    setInvocationArgument(invocation, index, units);
  }

  /**
   * Sets {@link MethodInvocation} argument is units.
   */
  private void setInvocationArgument(MethodInvocation invocation, int index, double units)
      throws Exception {
    getEditor().replaceInvocationArgument(invocation, index, SIZE_FORMAT.format(units));
  }

  /**
   * Sets {@link MethodInvocation} "unit" argument, with converting value.
   */
  private void changeInvocationUnit(MethodInvocation invocation,
      int index,
      Object newUnit,
      boolean horizontal) throws Exception {
    if (newUnit instanceof String) {
      newUnit = getUnitByName((String) newUnit);
    }
    // prepare value in pixels
    double pixels;
    {
      double oldValue = getValue(invocation, index - 1);
      Object oldUnit = getUnit(invocation, index);
      pixels = oldValue * getUnitSize(oldUnit, horizontal);
    }
    // convert value
    double newUnitSize = getUnitSize(newUnit, horizontal);
    if (newUnitSize > 0.0) {
      double newValue = pixels / newUnitSize;
      setInvocationArgument(invocation, index - 1, newValue);
      setInvocationUnit(invocation, index, newUnit);
    }
  }

  /**
   * Sets {@link MethodInvocation} "unit" argument, without converting value.
   */
  private void setInvocationUnit(MethodInvocation invocation, int index, Object unit)
      throws Exception {
    Expression expression =
        getEditor().replaceInvocationArgument(
            invocation,
            index,
            "com.google.gwt.dom.client.Style.Unit." + unit.toString());
    JavaInfoEvaluationHelper.setValue(expression, unit);
  }

  /**
   * @return the default size for new {@link WidgetInfo}.
   */
  private static Dimension getDefaultSize(WidgetInfo widget) {
    return widget.getBounds().getSize();
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.model.widgets.panels.LayoutPanelInfo

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.