blob: cfdd0b2cc6d30ea25dcf7e3022b11a11c41a4e9f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) 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:
* Soyatec - initial API and implementation
*******************************************************************************/
package org.eclipse.xwt.tools.ui.designer.commands;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.xwt.IConstants;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.swt.widgets.Group;
import org.eclipse.xwt.tools.ui.designer.core.util.StringUtil;
import org.eclipse.xwt.tools.ui.designer.layouts.LayoutType;
import org.eclipse.xwt.tools.ui.designer.parts.CompositeEditPart;
import org.eclipse.xwt.tools.ui.designer.parts.SashFormEditPart;
import org.eclipse.xwt.tools.ui.designer.parts.WidgetEditPart;
import org.eclipse.xwt.tools.ui.designer.policies.layout.ILayoutEditPolicy;
import org.eclipse.xwt.tools.ui.designer.policies.layout.grid.GridLayoutPolicyHelper;
import org.eclipse.xwt.tools.ui.designer.policies.layout.grid.GridLayoutPolicyHelper.GridComponent;
import org.eclipse.xwt.tools.ui.xaml.XamlAttribute;
import org.eclipse.xwt.tools.ui.xaml.XamlElement;
import org.eclipse.xwt.tools.ui.xaml.XamlFactory;
import org.eclipse.xwt.tools.ui.xaml.XamlNode;
import org.eclipse.xwt.tools.ui.xaml.tools.AnnotationTools;
/**
* @author jliu (jin.liu@soyatec.com)
*/
public class SurroundWithCommand extends Command {
protected List<EditPart> selectedObjects;
protected List<WidgetEditPart> surroundings;
protected Class<?> type;
protected EditPart parent;
protected LayoutType layoutType;
protected Command executeCommand;
public SurroundWithCommand(List<EditPart> selectedObjects) {
this.selectedObjects = selectedObjects;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.commands.Command#canExecute()
*/
public boolean canExecute() {
if (selectedObjects == null || selectedObjects.isEmpty()) {
return false;
}
// Check parent, all selected objects should have a same parent.
for (EditPart child : selectedObjects) {
if (parent == null) {
parent = child.getParent();
} else if (parent != child.getParent()) {
return false;
}
Object model = child.getModel();
if (model instanceof EObject) {
EObject object = (EObject) model;
if (object.eContainer() == null) {
return false;
}
}
}
if (parent == null) {
return false;
}
ILayoutEditPolicy layoutEdiPolicy = (ILayoutEditPolicy) parent.getAdapter(ILayoutEditPolicy.class);
if (layoutEdiPolicy == null) {
return false;
}
layoutType = layoutEdiPolicy.getType();
surroundings = new ArrayList<WidgetEditPart>();
// do quickly check
if (selectedObjects.size() == 1) {
EditPart editPart = selectedObjects.get(0);
if (!(editPart instanceof WidgetEditPart)) {
return false;
} else if (((WidgetEditPart) editPart).isRoot()) {
return false;
}
surroundings.add((WidgetEditPart) editPart);
return true;
}
if (layoutType == LayoutType.GridLayout) {
//
// TODO: make a smart check.
//
int min = -1, max = -1;
XamlNode parentNode = (XamlNode) parent.getModel();
EList<XamlElement> childNodes = parentNode.getChildNodes();
for (EditPart child : selectedObjects) {
XamlNode node = (XamlNode) child.getModel();
int index = childNodes.indexOf(node);
if (min == -1) {
min = index;
} else {
min = Math.min(min, index);
}
if (max == -1) {
max = index;
} else {
max = Math.max(max, index);
}
}
for (int i = min; i <= max; i++) {
XamlElement child = childNodes.get(i);
Object childEp = parent.getViewer().getEditPartRegistry().get(child);
if (AnnotationTools.isAnnotated(child, GridLayoutPolicyHelper.FILLER_DATA)) {
surroundings.add((WidgetEditPart) childEp);
} else if (selectedObjects.contains(childEp)) {
surroundings.add((WidgetEditPart) childEp);
} else {
return false;
}
}
} else {
for (EditPart child : selectedObjects) {
if (child instanceof WidgetEditPart) {
surroundings.add((WidgetEditPart) child);
}
}
}
return layoutType != null && !surroundings.isEmpty();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.commands.Command#execute()
*/
public void execute() {
XamlNode parentModel = (XamlNode) parent.getModel();
sort(surroundings, parentModel.getChildNodes());
CompoundCommand commands = new CompoundCommand();
XamlElement newParent = createParent();
if (parent instanceof SashFormEditPart) {
int index = -1;
for (WidgetEditPart child : surroundings) {
XamlElement castModel = (XamlElement) child.getCastModel();
if (index == -1) {
index = parentModel.getChildNodes().indexOf(castModel);
}
XamlElement newChild = (XamlElement) EcoreUtil.copy(castModel);
newParent.getChildNodes().add(newChild);
}
commands.add(new AddNewChildCommand(parentModel, newParent, index));
}
else if (LayoutType.NullLayout == layoutType) {
int x = -1, y = -1, right = 0, bottom = 0;
for (WidgetEditPart child : surroundings) {
Rectangle r = child.getVisualInfo().getBounds();
if (x == -1) {
x = r.x;
} else {
x = Math.min(x, r.x);
}
if (y == -1) {
y = r.y;
} else {
y = Math.min(y, r.y);
}
right = Math.max(right, r.right());
bottom = Math.max(bottom, r.bottom());
}
XamlAttribute boundsAttr = XamlFactory.eINSTANCE.createAttribute("bounds", IConstants.XWT_NAMESPACE);
boundsAttr.setValue(StringUtil.format(new Rectangle(x, y, right - x, bottom - y)));
newParent.getAttributes().add(boundsAttr);
for (WidgetEditPart child : surroundings) {
XamlElement castModel = (XamlElement) child.getCastModel();
Rectangle r = child.getVisualInfo().getBounds().getCopy();
r.translate(-x, -y);
XamlElement newChild = (XamlElement) EcoreUtil.copy(castModel);
ChangeConstraintCommand cmd = new ChangeConstraintCommand(newChild, r);
cmd.execute();
newParent.getChildNodes().add(newChild);
}
commands.add(new AddNewChildCommand(parentModel, newParent));
} else if (LayoutType.GridLayout == layoutType) {
int numRows = -1, numColumns = 0;
if (surroundings.size() == 1) {
numRows = numColumns = 1;
} else {
GridLayoutPolicyHelper helper = new GridLayoutPolicyHelper();
helper.setHost((CompositeEditPart) parent);
GridComponent[][] layoutTable = helper.getLayoutTable();
for (int i = 0; i < layoutTable.length; i++) {
GridComponent[] cells = layoutTable[i];
int row = 0;
boolean recorded = false;
for (int j = 0; j < cells.length; j++) {
GridComponent cell = cells[j];
XamlNode model = cell.getModel();
Object childEp = parent.getViewer().getEditPartRegistry().get(model);
if (!surroundings.contains(childEp)) {
continue;
}
if (!recorded) {
int span = cell.getSpanWidth();
if (span > 1) {
numColumns += span;
} else {
numColumns++;
}
recorded = true;
}
int spanHeight = cell.getSpanHeight();
if (spanHeight > 1) {
row += spanHeight;
} else {
row++;
}
}
numRows = Math.max(numRows, row);
}
}
int index = -1;
EList<XamlElement> childNodes = parentModel.getChildNodes();
for (WidgetEditPart child : surroundings) {
XamlElement castModel = (XamlElement) child.getCastModel();
int i = childNodes.indexOf(castModel);
if (index == -1) {
index = i;
} else {
index = Math.min(index, i);
}
XamlElement newChild = (XamlElement) EcoreUtil.copy(castModel);
newParent.getChildNodes().add(newChild);
}
// GridLayout
XamlElement gridLayout = XamlFactory.eINSTANCE.createElement("GridLayout", IConstants.XWT_NAMESPACE);
XamlAttribute numColumnsAttr = XamlFactory.eINSTANCE.createAttribute("numColumns", IConstants.XWT_NAMESPACE);
numColumnsAttr.setValue(Integer.toString(numColumns));
gridLayout.getAttributes().add(numColumnsAttr);
XamlAttribute gridLayoutAttr = XamlFactory.eINSTANCE.createAttribute("layout", IConstants.XWT_NAMESPACE);
gridLayoutAttr.getChildNodes().add(gridLayout);
newParent.getAttributes().add(gridLayoutAttr);
// GridData
XamlElement gridData = XamlFactory.eINSTANCE.createElement("GridData", IConstants.XWT_NAMESPACE);
createAttr(gridData, "horizontalAlignment", "SWT.FILL");
createAttr(gridData, "verticalAlignment", "SWT.FILL");
// createAttr(gridData, "grabExcessHorizontalSpace", "true");
// createAttr(gridData, "grabExcessVerticalSpace", "true");
createAttr(gridData, "horizontalSpan", Integer.toString(numColumns));
createAttr(gridData, "verticalSpan", Integer.toString(numRows));
XamlAttribute gridDataAttr = XamlFactory.eINSTANCE.createAttribute("layoutData", IConstants.XWT_NAMESPACE);
gridDataAttr.getChildNodes().add(gridData);
newParent.getAttributes().add(gridDataAttr);
commands.add(new AddNewChildCommand(parentModel, newParent, index));
} else if (LayoutType.RowLayout == layoutType || LayoutType.FillLayout == layoutType) {
XamlAttribute a = parentModel.getAttribute("layout");
if (a != null) {
XamlAttribute layoutAttr = (XamlAttribute) EcoreUtil.copy(a);
newParent.getAttributes().add(layoutAttr);
}
int index = -1;
EList<XamlElement> childNodes = parentModel.getChildNodes();
for (WidgetEditPart child : surroundings) {
XamlElement castModel = (XamlElement) child.getCastModel();
int i = childNodes.indexOf(castModel);
if (index == -1) {
index = i;
} else {
index = Math.min(index, i);
}
XamlElement newChild = (XamlElement) EcoreUtil.copy(castModel);
newParent.getChildNodes().add(newChild);
}
commands.add(new AddNewChildCommand(parentModel, newParent, index));
}
List<XamlNode> forDelete = new ArrayList<XamlNode>();
for (WidgetEditPart node : surroundings) {
forDelete.add(node.getCastModel());
}
commands.add(new DeleteCommand(forDelete));
executeCommand = commands.unwrap();
if (executeCommand.canExecute()) {
executeCommand.execute();
}
}
private void sort(List<WidgetEditPart> surroundings, final List<XamlElement> childNodes) {
Collections.sort(surroundings, new Comparator<WidgetEditPart>() {
public int compare(WidgetEditPart o1, WidgetEditPart o2) {
int i1 = childNodes.indexOf(o1.getCastModel());
int i2 = childNodes.indexOf(o2.getCastModel());
return i1 - i2;
}
});
}
private XamlAttribute createAttr(XamlNode parent, String name, String value) {
XamlAttribute attr = XamlFactory.eINSTANCE.createAttribute(name, IConstants.XWT_NAMESPACE);
attr.setValue(value);
parent.getAttributes().add(attr);
return attr;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.commands.Command#undo()
*/
public void undo() {
executeCommand.undo();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.commands.Command#canUndo()
*/
public boolean canUndo() {
return executeCommand != null && executeCommand.canUndo();
}
protected XamlElement createParent() {
XamlElement newParent = XamlFactory.eINSTANCE.createElement(type.getSimpleName(), IConstants.XWT_NAMESPACE);
if (Group.class == type) {
XamlAttribute textAttr = XamlFactory.eINSTANCE.createAttribute("text", IConstants.XWT_NAMESPACE);
textAttr.setValue("New Group");
newParent.getAttributes().add(textAttr);
}
return newParent;
}
/**
* @param type
* the type to set
*/
public void setType(Class<?> type) {
this.type = type;
}
/**
* @return the type
*/
public Class<?> getType() {
return type;
}
static class Counter {
List<Integer> indexes;
int count = 0;
void add(int index, int span) {
if (indexes == null) {
indexes = new ArrayList<Integer>();
}
if (indexes.contains(index)) {
return;
}
indexes.add(index);
if (span == 0) {
count++;
} else {
count += span;
}
}
}
}