/*******************************************************************************
* 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();
}
}