blob: 1f1f735318c8c2f2f2682c897841f9afbd925927 [file] [log] [blame]
/*
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.igv.graph;
import com.sun.hotspot.igv.data.InputBlock;
import com.sun.hotspot.igv.data.InputGraph;
import com.sun.hotspot.igv.data.InputNode;
import com.sun.hotspot.igv.data.Properties;
import com.sun.hotspot.igv.data.Source;
import com.sun.hotspot.igv.layout.Cluster;
import com.sun.hotspot.igv.layout.Vertex;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.*;
public class Figure extends Properties.Entity implements Source.Provider, Vertex {
public static final int INSET = 8;
public static int SLOT_WIDTH = 10;
public static final int OVERLAPPING = 6;
public static final int SLOT_START = 4;
public static final int SLOT_OFFSET = 8;
public static final boolean VERTICAL_LAYOUT = true;
protected List<InputSlot> inputSlots;
protected List<OutputSlot> outputSlots;
private Source source;
private Diagram diagram;
private Point position;
private List<Figure> predecessors;
private List<Figure> successors;
private List<InputGraph> subgraphs;
private Color color;
private int id;
private String idString;
private String[] lines;
private int heightCash = -1;
private int widthCash = -1;
public int getHeight() {
if (heightCash == -1) {
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setFont(diagram.getFont().deriveFont(Font.BOLD));
FontMetrics metrics = g.getFontMetrics();
String nodeText = diagram.getNodeText();
heightCash = nodeText.split("\n").length * metrics.getHeight() + INSET;
}
return heightCash;
}
public static <T> List<T> getAllBefore(List<T> inputList, T tIn) {
List<T> result = new ArrayList<>();
for(T t : inputList) {
if(t.equals(tIn)) {
break;
}
result.add(t);
}
return result;
}
public static int getSlotsWidth(Collection<? extends Slot> slots) {
int result = Figure.SLOT_OFFSET;
for(Slot s : slots) {
result += s.getWidth() + Figure.SLOT_OFFSET;
}
return result;
}
public int getWidth() {
if (widthCash == -1) {
int max = 0;
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setFont(diagram.getFont().deriveFont(Font.BOLD));
FontMetrics metrics = g.getFontMetrics();
for (String s : getLines()) {
int cur = metrics.stringWidth(s);
if (cur > max) {
max = cur;
}
}
widthCash = max + INSET;
widthCash = Math.max(widthCash, Figure.getSlotsWidth(inputSlots));
widthCash = Math.max(widthCash, Figure.getSlotsWidth(outputSlots));
}
return widthCash;
}
protected Figure(Diagram diagram, int id) {
this.diagram = diagram;
this.source = new Source();
inputSlots = new ArrayList<>(5);
outputSlots = new ArrayList<>(1);
predecessors = new ArrayList<>(6);
successors = new ArrayList<>(6);
this.id = id;
idString = Integer.toString(id);
this.position = new Point(0, 0);
this.color = Color.WHITE;
}
public int getId() {
return id;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
public List<Figure> getPredecessors() {
return Collections.unmodifiableList(predecessors);
}
public Set<Figure> getPredecessorSet() {
Set<Figure> result = new HashSet<>();
for (Figure f : getPredecessors()) {
result.add(f);
}
return Collections.unmodifiableSet(result);
}
public Set<Figure> getSuccessorSet() {
Set<Figure> result = new HashSet<>();
for (Figure f : getSuccessors()) {
result.add(f);
}
return Collections.unmodifiableSet(result);
}
public List<Figure> getSuccessors() {
return Collections.unmodifiableList(successors);
}
protected void addPredecessor(Figure f) {
this.predecessors.add(f);
}
protected void addSuccessor(Figure f) {
this.successors.add(f);
}
protected void removePredecessor(Figure f) {
assert predecessors.contains(f);
predecessors.remove(f);
}
protected void removeSuccessor(Figure f) {
assert successors.contains(f);
successors.remove(f);
}
public List<InputGraph> getSubgraphs() {
return subgraphs;
}
public void setSubgraphs(List<InputGraph> subgraphs) {
this.subgraphs = subgraphs;
}
@Override
public void setPosition(Point p) {
this.position = p;
}
@Override
public Point getPosition() {
return position;
}
public Diagram getDiagram() {
return diagram;
}
@Override
public Source getSource() {
return source;
}
public InputSlot createInputSlot() {
InputSlot slot = new InputSlot(this, -1);
inputSlots.add(slot);
return slot;
}
public InputSlot createInputSlot(int index) {
InputSlot slot = new InputSlot(this, index);
inputSlots.add(slot);
Collections.sort(inputSlots, Slot.slotIndexComparator);
return slot;
}
public void removeSlot(Slot s) {
assert inputSlots.contains(s) || outputSlots.contains(s);
List<Connection> connections = new ArrayList<>(s.getConnections());
for (Connection c : connections) {
c.remove();
}
if (inputSlots.contains(s)) {
inputSlots.remove(s);
} else if (outputSlots.contains(s)) {
outputSlots.remove(s);
}
}
public OutputSlot createOutputSlot() {
OutputSlot slot = new OutputSlot(this, -1);
outputSlots.add(slot);
return slot;
}
public OutputSlot createOutputSlot(int index) {
OutputSlot slot = new OutputSlot(this, index);
outputSlots.add(slot);
Collections.sort(outputSlots, Slot.slotIndexComparator);
return slot;
}
public List<InputSlot> getInputSlots() {
return Collections.unmodifiableList(inputSlots);
}
public Set<Slot> getSlots() {
Set<Slot> result = new HashSet<>();
result.addAll(getInputSlots());
result.addAll(getOutputSlots());
return result;
}
public List<OutputSlot> getOutputSlots() {
return Collections.unmodifiableList(outputSlots);
}
void removeInputSlot(InputSlot s) {
s.removeAllConnections();
inputSlots.remove(s);
}
void removeOutputSlot(OutputSlot s) {
s.removeAllConnections();
outputSlots.remove(s);
}
public String[] getLines() {
if (lines == null) {
updateLines();
}
return lines;
}
public void updateLines() {
String[] strings = diagram.getNodeText().split("\n");
String[] result = new String[strings.length];
for (int i = 0; i < strings.length; i++) {
result[i] = resolveString(strings[i], getProperties());
}
lines = result;
}
public static final String resolveString(String string, Properties properties) {
StringBuilder sb = new StringBuilder();
boolean inBrackets = false;
StringBuilder curIdent = new StringBuilder();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (inBrackets) {
if (c == ']') {
String value = properties.get(curIdent.toString());
if (value == null) {
value = "";
}
sb.append(value);
inBrackets = false;
} else {
curIdent.append(c);
}
} else {
if (c == '[') {
inBrackets = true;
curIdent = new StringBuilder();
} else {
sb.append(c);
}
}
}
return sb.toString();
}
@Override
public Dimension getSize() {
if (VERTICAL_LAYOUT) {
int width = Math.max(getWidth(), Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1));
int height = getHeight() + 2 * Figure.SLOT_WIDTH - 2 * Figure.OVERLAPPING;
return new Dimension(width, height);
} else {
int width = getWidth() + 2 * Figure.SLOT_WIDTH - 2*Figure.OVERLAPPING;
int height = Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1);
return new Dimension(width, height);
}
}
@Override
public String toString() {
return idString;
}
public Cluster getCluster() {
if (getSource().getSourceNodes().size() == 0) {
assert false : "Should never reach here, every figure must have at least one source node!";
return null;
} else {
final InputBlock inputBlock = diagram.getGraph().getBlock(getSource().getSourceNodes().get(0));
assert inputBlock != null;
Cluster result = diagram.getBlock(inputBlock);
assert result != null;
return result;
}
}
@Override
public boolean isRoot() {
List<InputNode> sourceNodes = source.getSourceNodes();
if (sourceNodes.size() > 0 && sourceNodes.get(0).getProperties().get("name") != null) {
return source.getSourceNodes().get(0).getProperties().get("name").equals("Root");
} else {
return false;
}
}
@Override
public int compareTo(Vertex f) {
return toString().compareTo(f.toString());
}
public Rectangle getBounds() {
return new Rectangle(this.getPosition(), new Dimension(this.getWidth(), this.getHeight()));
}
}