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