blob: a468487141812d97f57e32e4dda29e28319632d1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2011 SpringSource, a divison of VMware, Inc. 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:
* SpringSource, a division of VMware, Inc. - initial API and implementation
* SAP AG - moving to Eclipse Libra project and enhancements
*******************************************************************************/
package org.eclipse.libra.framework.editor.ui.internal.dependencies;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.libra.framework.editor.core.model.IBundle;
import org.eclipse.zest.core.widgets.GraphNode;
import org.eclipse.zest.core.widgets.ZestStyles;
import org.eclipse.zest.layouts.LayoutEntity;
import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm;
import org.eclipse.zest.layouts.dataStructures.InternalNode;
import org.eclipse.zest.layouts.dataStructures.InternalRelationship;
/**
* @author Christian Dupuis
* @author Kaloyan Raev
*/
public class BundleDependencyLayoutAlgorithm extends AbstractLayoutAlgorithm {
private final BundleDependencyContentProvider contentProvider;
public BundleDependencyLayoutAlgorithm(BundleDependencyContentProvider contentProvider) {
super(ZestStyles.NODES_NO_LAYOUT_RESIZE);
this.contentProvider = contentProvider;
}
@Override
protected void applyLayoutInternal(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider,
double boundsX, double boundsY, double boundsWidth, double boundsHeight) {
BundleDependencyContentResult contentResult = this.contentProvider.getContentResult();
if (contentResult != null) {
Set<IBundle> rootBundles = contentResult.getBundles();
Set<IBundle> bundlesProcessed = new HashSet<IBundle>();
Set<ColumnHolder> columnNodes = new HashSet<ColumnHolder>();
double columnWith = 0;
double currentX = boundsX + 0;
double currentY = boundsY + 10;
double maxY = boundsHeight;
// Start with the incoming dependencies
int degree = contentResult.getIncomingDegree().intValue();
while (degree > 0) {
Set<InternalNode> degreeNodes = new HashSet<InternalNode>();
Set<IBundle> deps = contentResult.getIncomingDependencies().get(Integer.valueOf(degree));
for (IBundle bundle : deps) {
if (!bundlesProcessed.contains(bundle)
&& !rootBundles.contains(bundle)
&& lowestRanking(bundle, degree,
contentResult.getIncomingDependencies()) == degree
) {
for (InternalNode node : entitiesToLayout) {
LayoutEntity obj = node.getLayoutEntity();
IBundle graphBundle = (IBundle) ((GraphNode) obj.getGraphData()).getData();
if (graphBundle.equals(bundle)) {
columnWith = Math.max(columnWith, node.getWidthInLayout());
node.setLocation(currentX, currentY);
bundlesProcessed.add(bundle);
currentY = currentY + node.getHeightInLayout() + 15;
degreeNodes.add(node);
maxY = Math.max(currentY, maxY);
break;
}
}
}
}
for (InternalNode node : degreeNodes) {
if (node.getWidthInLayout() < columnWith) {
double x = (columnWith - node.getWidthInLayout()) / 2;
node.setLocation(node.getLayoutEntity().getXInLayout() + x, node.getLayoutEntity()
.getYInLayout());
}
}
ColumnHolder holder = new ColumnHolder();
holder.y = currentY;
holder.nodes = degreeNodes;
columnNodes.add(holder);
currentY = boundsY + 10;
if (degreeNodes.size() > 0) {
currentX = currentX + columnWith + 30;
}
degree--;
columnWith = 0;
}
Set<InternalNode> rootNodes = new HashSet<InternalNode>();
for (IBundle bundle : rootBundles) {
for (InternalNode node : entitiesToLayout) {
LayoutEntity obj = node.getLayoutEntity();
IBundle graphBundle = (IBundle) ((GraphNode) obj.getGraphData()).getData();
if (graphBundle.equals(bundle)) {
columnWith = Math.max(columnWith, node.getWidthInLayout());
node.setLocation(currentX, currentY);
bundlesProcessed.add(bundle);
currentY = currentY + node.getHeightInLayout() + 15;
maxY = Math.max(currentY, maxY);
rootNodes.add(node);
break;
}
}
}
for (InternalNode node : rootNodes) {
if (node.getWidthInLayout() < columnWith) {
double x = (columnWith - node.getWidthInLayout()) / 2;
node.setLocation(node.getLayoutEntity().getXInLayout() + x, node.getLayoutEntity().getYInLayout());
}
}
ColumnHolder holder = new ColumnHolder();
holder.y = currentY;
holder.nodes = rootNodes;
columnNodes.add(holder);
currentY = boundsY + 10;
currentX = currentX + columnWith + 30;
int maxDegree = contentResult.getOutgoingDegree().intValue();
degree = 1;
while (degree <= maxDegree) {
Set<InternalNode> degreeNodes = new HashSet<InternalNode>();
Set<IBundle> deps = contentResult.getOutgoingDependencies().get(Integer.valueOf(degree));
for (IBundle bundle : deps) {
if (!bundlesProcessed.contains(bundle)
&& !rootBundles.contains(bundle)
&& lowestRanking(bundle, maxDegree, contentResult
.getOutgoingDependencies()) == degree) {
for (InternalNode node : entitiesToLayout) {
LayoutEntity obj = node.getLayoutEntity();
IBundle graphBundle = (IBundle) ((GraphNode) obj.getGraphData()).getData();
if (graphBundle.equals(bundle)) {
columnWith = Math.max(columnWith, node.getWidthInLayout());
node.setLocation(currentX, currentY);
bundlesProcessed.add(bundle);
currentY = currentY + node.getHeightInLayout() + 15;
maxY = Math.max(currentY, maxY);
degreeNodes.add(node);
break;
}
}
}
}
for (InternalNode node : degreeNodes) {
if (node.getWidthInLayout() < columnWith) {
double x = (columnWith - node.getWidthInLayout()) / 2;
node.setLocation(node.getLayoutEntity().getXInLayout() + x, node.getLayoutEntity()
.getYInLayout());
}
}
holder = new ColumnHolder();
holder.y = currentY;
holder.nodes = degreeNodes;
columnNodes.add(holder);
currentY = boundsY + 10;
currentX = currentX + columnWith + 30;
degree++;
columnWith = 0;
}
for (ColumnHolder column : columnNodes) {
if (column.y <= maxY) {
double y = (maxY - column.y) / 2;
for (InternalNode node : column.nodes) {
node.setLocation(node.getLayoutEntity().getXInLayout(), node.getLayoutEntity().getYInLayout()
+ y);
}
}
}
}
}
private static int lowestRanking(IBundle bundle, int maxDegree, Map<Integer, Set<IBundle>> bundles) {
int ranking = 1;
while (ranking <= maxDegree) {
for (IBundle b : bundles.get(Integer.valueOf(ranking))) {
if (b.equals(bundle)) {
return ranking;
}
}
ranking++;
}
return ranking;
}
@Override
protected int getCurrentLayoutStep() {
return 1;
}
@Override
protected int getTotalNumberOfLayoutSteps() {
return 1;
}
@Override
protected boolean isValidConfiguration(boolean asynchronous, boolean continuous) {
return true;
}
@Override
protected void postLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider) {
// nothing
}
@Override
protected void preLayoutAlgorithm(InternalNode[] entitiesToLayout, InternalRelationship[] relationshipsToConsider,
double x, double y, double width, double height) {
// nothing
}
@Override
public void setLayoutArea(double x, double y, double width, double height) {
// nothing
}
static class ColumnHolder {
protected double y;
protected Set<InternalNode> nodes;
}
}