/* FeatureIDE - An IDE to support feature-oriented software development * Copyright (C) 2005-2009 FeatureIDE Team, University of Magdeburg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * See http://www.fosd.de/featureide/ for further information. */ package featureide.fm.ui.editors.featuremodel.layouts; import java.util.Vector; import org.eclipse.draw2d.geometry.Point; import featureide.fm.core.Feature; import featureide.fm.core.FeatureModel; import featureide.fm.ui.editors.FeatureUIHelper; /** * Layouts the features at the feature diagram using a reverse level order search. * * @author Thomas Thuem */ public class LevelOrderLayout extends FeatureDiagramLayoutManager { private int featureDiagramBottom = 0; public void layout(FeatureModel featureModel) { layout(featureModel.getRoot()); layout(featureDiagramBottom, featureModel.getConstraints()); } private void layout(Feature root) { Vector<Vector<Feature>> levels = calculateLevels(root); for (int i = levels.size() - 1; i >= 0; i--) { int y = LAYOUT_MARGIN_Y + FEATURE_SPACE_Y * i; for (Feature feature : levels.get(i)) FeatureUIHelper.setLocation(feature,new Point(0, y)); for (Feature feature : levels.get(i)) if (feature.hasChildren()) { centerAboveChildren(feature); } Feature lastFeature = null; int moveWidth = 0; for (int j = 0; j < levels.get(i).size(); j++) { Feature feature = levels.get(i).get(j); if (!feature.hasChildren()) nextToSibling(feature, lastFeature); else { if (lastFeature != null) moveWidth = Math.max(moveWidth, FeatureUIHelper.getBounds(lastFeature).right() + FEATURE_SPACE_X - FeatureUIHelper.getLocation(feature).x); if (moveWidth > 0) moveTree(feature, moveWidth); int width = FEATURE_SPACE_X; int l = 0; int space = 0; boolean right = true; for (int k = j - 1; k >= 0; k--) { Feature sibling = levels.get(i).get(k); if (sibling.getParent() != feature.getParent()) { l = k + 1; break; } if (sibling.hasChildren()) { l = k + 1; right = false; space = FeatureUIHelper.getBounds(feature).x - FeatureUIHelper.getBounds(sibling).right() - width; break; } width += FeatureUIHelper.getSize(sibling).width + FEATURE_SPACE_X; } if (right) space = FeatureUIHelper.getBounds(feature).x - (FeatureUIHelper.getBounds(levels.get(i).get(l)).x - FEATURE_SPACE_X) - width; for (int k = l; k < j; k++) { Feature sibling = levels.get(i).get(k); if (right) moveTree(sibling, space); else moveTree(sibling, space * (k - l + 1) / (j - l + 1)); } } lastFeature = feature; } } int newX = (controlWidth - FeatureUIHelper.getBounds(root).width) / 2; moveTree(root, newX - FeatureUIHelper.getLocation(root).x); featureDiagramBottom = LAYOUT_MARGIN_Y + FEATURE_SPACE_Y * (levels.size() - 1); } private Vector<Vector<Feature>> calculateLevels(Feature root) { Vector<Vector<Feature>> levels = new Vector<Vector<Feature>>(); Vector<Feature> level = new Vector<Feature>(); level.add(root); while (!level.isEmpty()) { levels.add(level); Vector<Feature> newLevel = new Vector<Feature>(); for (Feature feature : level) for (Feature child : feature.getChildren()) newLevel.add(child); level = newLevel; } return levels; } private void centerAboveChildren(Feature feature) { int minX = FeatureUIHelper.getBounds(feature.getFirstChild()).x; int maxX = FeatureUIHelper.getBounds(feature.getLastChild()).right(); Point location = FeatureUIHelper.getLocation(feature); int x = (maxX + minX) / 2 - FeatureUIHelper.getSize(feature).width / 2; FeatureUIHelper.setLocation(feature,new Point(x, location.y)); } private void nextToSibling(Feature feature, Feature lastFeature) { Point location = FeatureUIHelper.getLocation(feature); int x = lastFeature != null ? FeatureUIHelper.getBounds(lastFeature).right() + FEATURE_SPACE_X : 0; FeatureUIHelper.setLocation(feature,new Point(x, location.y)); } private void moveTree(Feature feature, int deltaX) { Point location = FeatureUIHelper.getLocation(feature); FeatureUIHelper.setLocation(feature,new Point(location.x + deltaX, location.y)); for (Feature child : feature.getChildren()) moveTree(child, deltaX); } }