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