/*******************************************************************************
* Copyright (c) 2006-2012
* Software Technology Group, Dresden University of Technology
* DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026
*
* 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:
* Software Technology Group - TU Dresden, Germany;
* DevBoost GmbH - Berlin, Germany
* - initial API and implementation
******************************************************************************/
/*
* Copyright (c) 2007 Borland Software Corporation
*
* 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:
* Dmitry Stadnik (Borland) - initial API and implementation
*/
package org.reuseware.application.taipan.layouts;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gmf.runtime.common.core.service.IOperation;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.ILayoutNodeOperation;
import org.eclipse.gmf.runtime.diagram.ui.services.layout.LayoutType;
import org.eclipse.gmf.runtime.notation.View;
import org.reuseware.application.taipan.Building;
import org.reuseware.application.taipan.Port;
/**
* Places buildings in rows by streets.
*
* @author dstadnik
*/
public class PortLayoutProvider extends AbstractLayoutEditPartProvider {
protected static final int GAP = 20;
private boolean working;
/**
* Returns true when layout is arranging buildings.
*/
public final boolean isWorking() {
return working;
}
public boolean provides(IOperation operation) {
View cview = getContainer(operation);
if (cview == null) {
return false;
}
IAdaptable layoutHint = ((ILayoutNodeOperation) operation).getLayoutHint();
String layoutType = (String) layoutHint.getAdapter(String.class);
return LayoutType.DEFAULT.equals(layoutType);
}
public Command layoutEditParts(@SuppressWarnings("rawtypes") List selectedObjects, IAdaptable layoutHint) {
GraphicalEditPart editPart = (GraphicalEditPart) selectedObjects.get(0);
GraphicalEditPart containerEditPart = (GraphicalEditPart) editPart.getParent();
return layoutEditParts(containerEditPart, layoutHint);
}
public Command layoutEditParts(GraphicalEditPart containerEditPart, IAdaptable layoutHint) {
return layoutPort(containerEditPart);
}
protected Command layoutPort(GraphicalEditPart portEditPart) {
assert portEditPart instanceof IGraphicalEditPart
&& ((IGraphicalEditPart) portEditPart).resolveSemanticElement() instanceof Port;
if (working) {
throw new IllegalStateException("Recursive layout invocation"); //$NON-NLS-1$
}
CompoundCommand cc = new CompoundCommand("Port Layout"); //$NON-NLS-1$
try {
working = true;
// separate buildings by streets
Map<String, Collection<IGraphicalEditPart>> rows =
new TreeMap<String, Collection<IGraphicalEditPart>>(); // street -> [BuildingEditPart]
for (Iterator<?> it = portEditPart.getChildren().iterator(); it.hasNext();) {
IGraphicalEditPart editPart = (IGraphicalEditPart) it.next();
EObject model = editPart.resolveSemanticElement();
if (model instanceof Building) {
Building building = (Building) model;
String street = building.getStreet() == null ? "" : building.getStreet(); //$NON-NLS-1$
Collection<IGraphicalEditPart> editParts = rows.get(street);
if (editParts == null) {
editParts = new TreeSet<IGraphicalEditPart>(new XComparator());
rows.put(street, editParts);
}
editParts.add(editPart);
}
}
// layout streets
int offset = GAP;
for (Iterator<String> it = rows.keySet().iterator(); it.hasNext();) {
Collection<IGraphicalEditPart> editParts = rows.get(it.next());
int thickness = getStreetThickness(editParts);
layoutStreet(editParts, offset, thickness, cc);
offset += thickness + GAP;
}
} finally {
working = false;
}
return cc.isEmpty() ? new Command("Nothing to layout") {} : cc; //$NON-NLS-1$
}
protected void layoutStreet(Collection<IGraphicalEditPart> editParts,
int yOffset, int thickness, CompoundCommand cc) {
int xOffset = GAP;
for (Iterator<IGraphicalEditPart> it = editParts.iterator(); it.hasNext();) {
GraphicalEditPart editPart = it.next();
Rectangle bounds = editPart.getFigure().getBounds();
Point newLocation = new Point(xOffset, yOffset);
editPart.getFigure().translateToAbsolute(newLocation);
Point oldLocation = bounds.getLocation();
editPart.getFigure().translateToAbsolute(oldLocation);
Dimension delta = newLocation.getDifference(oldLocation);
if (delta.width != 0 || delta.height != 0) {
ChangeBoundsRequest request = new ChangeBoundsRequest(RequestConstants.REQ_MOVE);
request.setEditParts(editPart);
request.setMoveDelta(new Point(delta.width, delta.height));
request.setLocation(newLocation);
Command cmd = editPart.getCommand(request);
if (cmd != null && cmd.canExecute()) {
cc.add(cmd);
}
}
xOffset += bounds.width + GAP;
}
}
protected int getStreetThickness(Collection<IGraphicalEditPart> editParts) {
int thickness = 0;
for (Iterator<IGraphicalEditPart> it = editParts.iterator(); it.hasNext();) {
int height = it.next().getFigure().getBounds().height;
if (height > thickness) {
thickness = height;
}
}
return thickness;
}
protected static class XComparator implements Comparator<IGraphicalEditPart> {
public int compare(IGraphicalEditPart p1, IGraphicalEditPart p2) {
int x1 = p1.getFigure().getBounds().x;
int x2 = p2.getFigure().getBounds().x;
return x1 - x2;
}
}
}