blob: 7a3e3d8f143ecddaeeedeb7c9176ed7e69663546 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2009, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.render.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.PrecisionRectangle;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Translatable;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.editparts.LayerManager;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.figures.IExpandableFigure;
/**
* Utility methods used by various diagram image generators
*
* @author aboyko
* @since 1.3
*
*/
public final class DiagramImageUtils {
/**
* Calculates the bounding box around given editparts. The bounding box is relative to printable layer
*
* @param editparts given editparts
* @param frameSize frame around the bounding box
* @param defaultSize if there are no editparts, the size of the bounding box will be the default one.
* @return the editparts bounding box
*/
public static final Rectangle calculateImageRectangle(
List<IGraphicalEditPart> editparts, double frameSize, Dimension defaultSize) {
double minX = editparts.isEmpty() ? 0 : Double.MAX_VALUE;
double maxX = editparts.isEmpty() ? 0 : Double.MIN_VALUE;
double minY = editparts.isEmpty() ? 0 : Double.MAX_VALUE;
double maxY = editparts.isEmpty() ? 0 : Double.MIN_VALUE;
IFigure printableLayer = null;
if (!editparts.isEmpty()) {
printableLayer = LayerManager.Helper.find(editparts.get(0))
.getLayer(LayerConstants.PRINTABLE_LAYERS);
}
for (IGraphicalEditPart editPart : editparts) {
IFigure figure = editPart.getFigure();
Rectangle bounds = null;
if (figure instanceof IExpandableFigure)
bounds = ((IExpandableFigure) figure).getExtendedBounds().getCopy();
else
bounds = figure.getBounds().getCopy();
translateTo(bounds, figure, printableLayer);
minX = Math.min(minX, bounds.preciseX());
maxX = Math.max(maxX, bounds.preciseX() + bounds.preciseWidth());
minY = Math.min(minY, bounds.preciseY());
maxY = Math.max(maxY, bounds.preciseY() + bounds.preciseHeight());
}
PrecisionRectangle rect = new PrecisionRectangle();
rect.preciseWidth = maxX - minX;
rect.preciseHeight = maxY - minY;
if (defaultSize != null) {
if (rect.preciseHeight <= 0) {
rect.preciseHeight = defaultSize.preciseWidth();
}
if (rect.preciseHeight <= 0) {
rect.preciseHeight = defaultSize.preciseHeight();
}
}
rect.preciseX = minX - frameSize;
rect.preciseY = minY - frameSize;
rect.preciseWidth += 2 * frameSize;
rect.preciseHeight += 2 * frameSize;
rect.updateInts();
return rect;
}
/**
* Translates <code>t</code> from one figure coordinate system to its ancestor figure coordinate system
*
* @param t the value to translate
* @param translateFrom initial figure
* @param translateTo some ancestor figure
* @return translated <code>t</code>
*/
public static final Translatable translateTo(Translatable t,
IFigure translateFrom, IFigure translateTo) {
for (IFigure walker = translateFrom; walker != null
&& walker != translateTo; walker = walker.getParent()) {
walker.translateToParent(t);
}
return t;
}
/**
* Sorts editparts using editparts figures z-order. All figures must be
* ancestors of <code>zOrderRoot</code> figure
*
* @param editparts
* list of editparts to sort
* @param zOrderRoot
* the common parent
* @since 1.3
*/
public static void zOrderSort(List<? extends GraphicalEditPart> editparts, IFigure zOrderRoot) {
if (editparts == null || editparts.size() < 2) {
return;
}
final Map<GraphicalEditPart, List<Integer>> indexMap = new IdentityHashMap<GraphicalEditPart, List<Integer>>(editparts.size());
for (GraphicalEditPart ep : editparts) {
List<Integer> index = new ArrayList<Integer>();
for (IFigure fig = ep.getFigure(); fig != zOrderRoot && fig.getParent() != null; fig = fig.getParent()) {
index.add(fig.getParent().getChildren().indexOf(fig));
}
indexMap.put(ep, index);
}
Collections.sort(editparts, new Comparator<GraphicalEditPart>() {
public int compare(GraphicalEditPart ep1, GraphicalEditPart ep2) {
List<Integer> index1 = indexMap.get(ep1);
List<Integer> index2 = indexMap.get(ep2);
int num1, num2;
for (int i = 0; i < index1.size() && i < index2.size(); i++) {
num1 = index1.get(index1.size() - 1 - i).intValue();
num2 = index2.get(index2.size() - 1 - i).intValue();
if (num1 < num2) {
return -1;
} else if (num1 > num2) {
return 1;
}
}
/*
* If we get here then either one editparts figure is the child of another one.
* Child figure will be on top of its parent.
* Parent figure will have smaller size of the index
*/
if (index1.size() < index2.size()) {
return 1;
} else if (index1.size() > index2.size()) {
return -1;
} else {
return 0;
}
}
});
}
}