All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.metaeffekt.dcc.docgenerator.ProfileLayout Maven / Gradle / Ivy

There is a newer version: 0.17.0
Show newest version
/**
 * Copyright 2009-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.metaeffekt.dcc.docgenerator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.metaeffekt.dcc.commons.mapping.Binding;
import org.metaeffekt.dcc.commons.mapping.ConfigurationUnit;
import org.metaeffekt.dcc.commons.mapping.Profile;
import org.metaeffekt.dcc.commons.mapping.PropertiesHolder;


public class ProfileLayout {

    public static final int CAPABILITY_WIDTH = 220;
    public static final int GRID_COLUMN_WIDTH = 2 * CAPABILITY_WIDTH + 70;
    public static final int CAPABILITY_HEIGHT = 32;
    public static final int CAPABILITY_DISTANCE = 3;

    private static final int MINIMUM_LEVEL_HEIGHT = 0;

    private Profile profile;
    
    private DocGenerator docGenerator;
    
    private int maxNumberOfUnitsInLevels = 0;
    private int maxNumberOfLevels = 0;
    
    private Map> unitGrid = 
        new HashMap<>();

    private Map rowHeights = new HashMap<>();

    private List nodes = new ArrayList<>();
    private Map unitNodeMap = new HashMap<>();
    
    public ProfileLayout(DocGenerator docGenerator, Profile profile) {
        this.docGenerator = docGenerator;
        this.profile = profile;

        List units = profile.getUnits(false);
        if (units == null || units.isEmpty()) {
            return;
        }
        
        PropertiesHolder propertiesHolder = profile.createPropertiesHolder(true);

        // layout pre-processing. distributes the units to different lanes / levels, according to
        // name categories
//        String[] categories = new String[] { "host", "runtime", "instance", "war", "webapp"};
        String[] categories = new String[] { "host", "runtime", "instance", "contribution", "war", "bundle", "import", "bootstrap", "config", "configuration", "webapp", "schema" };
       
        int[] offsets = new int[categories.length];
        int laneIndex = 0;
        for (int i = 0; i < categories.length; i++) {
            boolean nodeInLane = false;
            for (Iterator iterator = units.iterator(); iterator.hasNext();) {
                ConfigurationUnit unit = iterator.next();
                if (isInCategory(unit, categories[i])) {
                    String x = propertiesHolder.getBaseProperty(unit.getId() + ".layout.x", null);
                    String y = propertiesHolder.getBaseProperty(unit.getId() + ".layout.y", null);

                    boolean fixed = false;

                    if (y == null) {
                        y = String.valueOf(laneIndex);
                    } else {
                        fixed = true;
                    }

                    if (x == null) {
                        x = String.valueOf(offsets[laneIndex]++);
                    } else {
                        fixed = true;
                    }
                    
                    Node node = new Node(unit, Integer.parseInt(x), Integer.parseInt(y));
                    node.setFixed(fixed);
                    unitNodeMap.put(unit, node);
                    nodes.add(node);
                    iterator.remove();
                    nodeInLane = true;
                }
            }
            if (nodeInLane) {
                laneIndex++;
            }
        }
        
        // distribute remaining (uncategorized units) to an additional lane
        int offset = 0;
        for (ConfigurationUnit unit : units) {
            Node node = unitNodeMap.get(unit);
            if (node != null && node.isFixed()) {
                continue;
            }
            
            String x = propertiesHolder.getBaseProperty(unit.getId() + ".layout.x", null);
            String y = propertiesHolder.getBaseProperty(unit.getId() + ".layout.y", null);

            boolean fixed = false;
            if (x == null) {
                x = String.valueOf(offset++);
            } else {
                fixed = true;
            }
            if (y == null) {
                y = String.valueOf(laneIndex);
            } else {
                fixed = true;
            }
            
            node = new Node(unit, Integer.parseInt(x), Integer.parseInt(y));
            node.setFixed(fixed);
            unitNodeMap.put(unit, node);
            nodes.add(node);
        }
        
//        for (ConfigurationUnit unit : units) {
//            Node node = unitNodeMap.get(unit);
//            if (node != null) {
//                if (!node.isFixed()) {
//                    node.setVisible(false);
//                    nodes.remove(node);
//                }
//            }
//        }
        
        int minX = 0, maxX = 0;
        int minY = 0, maxY = 0;
        
        int iterations = 20;
        
        for (int i = 0; i < iterations; i++) {
            
            // sequentially apply forces to the current node
            for (Node node : nodes) {
                node.applyForces(profile, nodes);
            }
            
            // after all nodes have been processed in an iteration these are normalized to the grid
            for (Node node : nodes) {
                node.normalizeToGrid();
            }
            
            // move in grid such that topmost at y=0, leftmost at x=0
            minX = maxX = nodes.get(0).getXOnGrid();
            minY = maxY = nodes.get(0).getYOnGrid();
            for (Node node : nodes) {
                minX = Math.min(minX, node.getXOnGrid());
                maxX = Math.max(maxX, node.getXOnGrid());
                minY = Math.min(minY, node.getYOnGrid());
                maxY = Math.max(maxY, node.getYOnGrid());
            }
            for (Node node : nodes) {
                node.add(-minX, -minY);
            }
            maxX -= minX;
            maxY -= minY;
        }

        avoidCollisions();
    
        // move in grid such that topmost at y=0, leftmost at x=0
        minX = maxX = nodes.get(0).getXOnGrid();
        minY = maxY = nodes.get(0).getYOnGrid();
        for (Node node : nodes) {
            minX = Math.min(minX, node.getXOnGrid());
            maxX = Math.max(maxX, node.getXOnGrid());
            minY = Math.min(minY, node.getYOnGrid());
            maxY = Math.max(maxY, node.getYOnGrid());
        }
        for (Node node : nodes) {
            node.add(-minX, -minY);
        }
        maxX -= minX;
        maxY -= minY;
        
        for (Node node : nodes) {
            List unitsInLevel = unitGrid.get(node.getYOnGrid());
            if (unitsInLevel == null) {
                unitsInLevel = new ArrayList<>();
                unitGrid.put(node.getYOnGrid(), unitsInLevel);
            }
            unitsInLevel.add(node);
        }
        
        // determine max width and height for grid
        for (int i = 0; i < unitGrid.size(); i++) {
            int max = MINIMUM_LEVEL_HEIGHT;
            final List nodes = unitGrid.get(i);
            if (nodes != null) {
                for (Node node: nodes) {
                    max = Math.max(max, computeHeight(node.getUnit()));
                }
            } 
            rowHeights.put(i, max);
        }
        maxNumberOfLevels = maxY + 1;
        maxNumberOfUnitsInLevels = maxX + 1;
    }

    public void avoidCollisions() {
        for (Node node : nodes) {
            node.moveToEmpty(nodes);
        }
    }
    
    private int computeHeight(ConfigurationUnit unit) {
        return (CAPABILITY_HEIGHT + CAPABILITY_DISTANCE) * docGenerator.computeHeight(unit) + 150;
    }

    public int computeOffsetX(ConfigurationUnit unit) {
        Integer level = determineLevelForUnit(unit);
        if (level == null) return 0;
        List unitsInLevel = unitGrid.get(level);

        if (unitsInLevel == null) {
            return 0;
        }
        
        int positionInLevel = unitNodeMap.get(unit).getXOnGrid();
        
        int offset = 0;
        for (int i = 0; i < positionInLevel; i++) {
            offset += GRID_COLUMN_WIDTH;
        }
        return offset;
    }
    
    public int computeOffsetXOnGrid(ConfigurationUnit unit) {
        return unitNodeMap.get(unit).getXOnGrid();
    }

    public int computeOffsetYOnGrid(ConfigurationUnit unit) {
        return unitNodeMap.get(unit).getYOnGrid();
    }

    public int computeOffsetY(ConfigurationUnit unit) {
        Integer level = determineLevelForUnit(unit);
        return getHeightForLevel(level);
    }

    public int getHeightForLevel(Integer level) {
        if (level == null) return 0;
        
        int offset = 0;
        for (int i = 0; i < level; i++) {
            if (rowHeights.get(i) != null) {
                offset += rowHeights.get(i);
            } else {
                offset += 600;
            }
        }
        return offset;
    }

    private Integer determineLevelForUnit(ConfigurationUnit unit) {
        Node node = unitNodeMap.get(unit);
        return node.getYOnGrid();
    }

    public boolean isInCategory(ConfigurationUnit unit, final String category) {
        String unitIdString = unit.getId().getValue();
        return unitIdString.startsWith(category+"-") ||
                unitIdString.endsWith("-"+category);
    }
    
    public BindingLayout computeBindingLayout(Binding binding) {
        return new BindingLayout(this, binding, unitNodeMap);
    }

    public Profile getProfile() {
        return profile;
    }
    
    public int getWidth() {
        return maxNumberOfUnitsInLevels * GRID_COLUMN_WIDTH + 100;
    }
    
    public int getHeight() {
        return getHeightForLevel(maxNumberOfLevels + 1) + 400;
    }
    
    public boolean isVisible(ConfigurationUnit unit) {
        Node node = unitNodeMap.get(unit);
        return node != null && node.isVisible(); 
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy