/* * CCVisu is a tool for visual graph clustering * and general force-directed graph layout. * This file is part of CCVisu. * * Copyright (C) 2005-2012 Dirk Beyer * * CCVisu is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * CCVisu 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CCVisu; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Please find the GNU Lesser General Public License in file * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt * * Dirk Beyer (firstname.lastname@uni-passau.de) * University of Passau, Bavaria, Germany */ package org.sosy_lab.ccvisu.graph; import java.awt.Color; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.sosy_lab.ccvisu.graph.GraphVertex.Shape; import org.sosy_lab.util.Colors; import com.google.common.collect.ImmutableList; /** * A class with a list of nodes that compute some informations on them */ public class Group implements Iterable<GraphVertex> { public enum GroupKind { USERDEFINED, CLUSTER }; /** name of the group */ private String name; /** list of nodes in the GraphData */ private SortedSet<GraphVertex> nodes = new TreeSet<GraphVertex>(); /** color of the group */ private Color color = Colors.RED.get(); /** shape of the group */ private Shape shape = Shape.DISC; /** kind of the group */ private GroupKind kind = GroupKind.USERDEFINED; /** a list of patterns to match strings */ private List<String> patterns = new ArrayList<String>(); /** true if needs to recompute radius, center, ... */ private boolean changed = true; /** the radius of the group */ private RadiusOfGroup radiusOfGroup = null; /** used to know if the group should be drawn */ private boolean visible = true; /** used to know if the circle and cross should be drawn */ private boolean drawInfo = false; /** pointer to the graph data */ private final GraphData graph; /** * Constructor * @param name the group's name */ public Group(String name, GraphData graphData) { this.name = name; this.graph = graphData; } /** * Constructor * @param name the group's name * @param color the group's color * @param shape the group's shape * @param graphData the group's graph data */ public Group(String name, Color color, Shape shape, GraphData graphData) { this.name = name; this.color = color; this.shape = shape; this.graph = graphData; } /** * Note: the 'graph' and 'nodes' fields aren't cloned, but just copied. */ @Override protected Group clone() { // TODO: transform this method into a copy constructor Group newGroup = new Group(name, color, shape, graph); newGroup.nodes = this.nodes; return newGroup; } /** * add the given node to the group * @param vertex */ public void addNode(GraphVertex vertex) { vertex.setColor(color); vertex.setShape(shape); addNode_WO_COLOR(vertex); } /** * add the node that corresponds to the index-th node in graph(GraphData) * without changing his color * function used only to assign to default group at initialization * @param vertex vertex to process */ public void addNode_WO_COLOR(GraphVertex vertex) { changed = true; Group clt = graph.findGroupOfVertex(vertex); if (clt != null) { clt.removeNode(vertex, false); } nodes.add(vertex); } /** * Remove the given node from the group. * @param vertex */ public void removeNode(GraphVertex vertex, boolean addToDefaultGroup) { nodes.remove(vertex); if (addToDefaultGroup) { graph.getDefaultGroup().addNode(vertex); } changed = true; } /** * return an iterator on the index of the group's nodes * @return iterator */ @Override public Iterator<GraphVertex> iterator() { return nodes.iterator(); } /** * adds nodes to a group in function of a given pattern * @param pattern * @param mode the way of using the pattern. */ public void addViaPattern(String pattern, PatternMode mode) { for (GraphVertex graphVertex : graph.getVertices()) { switch (mode) { case CONTAINS: if (graphVertex.getName().matches(".*" + pattern + ".*")) { addNode(graphVertex); } break; case ENDS: if (graphVertex.getName().endsWith(pattern)) { addNode(graphVertex); } break; case EQUALS: if (graphVertex.getName().equals(pattern)) { addNode(graphVertex); } break; case STARTS: if (graphVertex.getName().startsWith(pattern)) { addNode(graphVertex); } break; } } } public void filter(String pattern, PatternMode mode, boolean keep) { Iterator<GraphVertex> it = getNodes().iterator(); while (it.hasNext()) { GraphVertex vertex = it.next(); String vertexName = vertex.getName(); boolean match = (mode == PatternMode.EQUALS && vertexName.equals(pattern)) || (mode == PatternMode.CONTAINS && vertexName.matches(".*" + pattern + ".*")) || (mode == PatternMode.STARTS && vertexName.startsWith(pattern)) || (mode == PatternMode.ENDS && vertexName.endsWith(pattern)); boolean remove = (match && !keep) || (!match && keep); if (remove) { removeNode(vertex, true); } } } public boolean contains(GraphVertex vertex) { return nodes.contains(vertex); } public List<GraphVertex> getNodes() { return ImmutableList.copyOf(nodes); } /** * @return return the color of the group. */ public Color getColor() { return color; } /** * @param color color to define. */ public void setColor(Color color) { this.color = color; for (GraphVertex vertex : nodes) { vertex.setColor(color); } } public Shape getShape() { return shape; } public void setShape(Shape shape) { assert (shape != null); this.shape = shape; for (GraphVertex graphVertex : nodes) { graphVertex.setShape(shape); } } public boolean matchPattern(String pName) { for (String pattern : patterns) { if (pName.matches(pattern)) { return true; } if (pName.equals(pattern)) { return true; } } return false; } public void addPattern(String pattern) { patterns.add(pattern); } /** * @return return the name of the group. */ public String getName() { return name; } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return return the name of the group. */ @Override public String toString() { return name; } /** * @return return the averageRadius. */ public float getAverageRadius() { if (changed) { compute(); } return radiusOfGroup.getAverageRadius(); } /** * @return return the maxRadius. */ public float getMaxRadius() { if (changed) { compute(); } return radiusOfGroup.getMaxRadius(); } /** * return the x-coordinate of the barycenter * @return x */ public float getX() { if (changed) { compute(); } return radiusOfGroup.getX(); } /** * return the y-coordinate of the barycenter * @return y */ public float getY() { if (changed) { compute(); } return radiusOfGroup.getY(); } /** * return the z-coordinate of the barycenter * @return z */ public float getZ() { if (changed) { compute(); } return radiusOfGroup.getZ(); } /** * compute the informations provided by the group */ private void compute() { radiusOfGroup = new RadiusOfGroup(nodes); changed = false; } /** * tells the group to recompute its informations */ public void graphChanged() { changed = true; } public void setNodes(List<GraphVertex> nodes) { this.nodes.clear(); this.nodes.addAll(nodes); } /** * @param kind the kind to set */ public void setKind(GroupKind kind) { this.kind = kind; } /** * @return the kind */ public GroupKind getKind() { return kind; } public boolean isVisible() { return visible; } public void setVisible(boolean visible) { this.visible = visible; } public boolean isDrawInfo() { return drawInfo; } public void setDrawInfo(boolean drawInfo) { this.drawInfo = drawInfo; } }