1 /*
2  * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 package com.sun.hotspot.igv.graph;
25 
26 import com.sun.hotspot.igv.data.InputBlock;
27 import com.sun.hotspot.igv.data.InputGraph;
28 import com.sun.hotspot.igv.data.InputNode;
29 import com.sun.hotspot.igv.data.Properties;
30 import com.sun.hotspot.igv.data.Source;
31 import com.sun.hotspot.igv.layout.Cluster;
32 import com.sun.hotspot.igv.layout.Vertex;
33 import java.awt.*;
34 import java.awt.image.BufferedImage;
35 import java.util.List;
36 import java.util.*;
37 
38 public class Figure extends Properties.Entity implements Source.Provider, Vertex {
39 
40     public static final int INSET = 8;
41     public static int SLOT_WIDTH = 10;
42     public static final int OVERLAPPING = 6;
43     public static final int SLOT_START = 4;
44     public static final int SLOT_OFFSET = 8;
45     public static final boolean VERTICAL_LAYOUT = true;
46     protected List<InputSlot> inputSlots;
47     protected List<OutputSlot> outputSlots;
48     private Source source;
49     private Diagram diagram;
50     private Point position;
51     private List<Figure> predecessors;
52     private List<Figure> successors;
53     private List<InputGraph> subgraphs;
54     private Color color;
55     private int id;
56     private String idString;
57     private String[] lines;
58     private int heightCash = -1;
59     private int widthCash = -1;
60 
getHeight()61     public int getHeight() {
62         if (heightCash == -1) {
63             BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
64             Graphics g = image.getGraphics();
65             g.setFont(diagram.getFont().deriveFont(Font.BOLD));
66             FontMetrics metrics = g.getFontMetrics();
67             String nodeText = diagram.getNodeText();
68             heightCash = nodeText.split("\n").length * metrics.getHeight() + INSET;
69         }
70         return heightCash;
71     }
72 
getAllBefore(List<T> inputList, T tIn)73     public static <T> List<T> getAllBefore(List<T> inputList, T tIn) {
74         List<T> result = new ArrayList<>();
75         for(T t : inputList) {
76             if(t.equals(tIn)) {
77                 break;
78             }
79             result.add(t);
80         }
81         return result;
82     }
83 
getSlotsWidth(Collection<? extends Slot> slots)84     public static int getSlotsWidth(Collection<? extends Slot> slots) {
85         int result = Figure.SLOT_OFFSET;
86         for(Slot s : slots) {
87             result += s.getWidth() + Figure.SLOT_OFFSET;
88         }
89         return result;
90     }
91 
getWidth()92     public int getWidth() {
93         if (widthCash == -1) {
94             int max = 0;
95             BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
96             Graphics g = image.getGraphics();
97             g.setFont(diagram.getFont().deriveFont(Font.BOLD));
98             FontMetrics metrics = g.getFontMetrics();
99             for (String s : getLines()) {
100                 int cur = metrics.stringWidth(s);
101                 if (cur > max) {
102                     max = cur;
103                 }
104             }
105             widthCash = max + INSET;
106             widthCash = Math.max(widthCash, Figure.getSlotsWidth(inputSlots));
107             widthCash = Math.max(widthCash, Figure.getSlotsWidth(outputSlots));
108         }
109         return widthCash;
110     }
111 
Figure(Diagram diagram, int id)112     protected Figure(Diagram diagram, int id) {
113         this.diagram = diagram;
114         this.source = new Source();
115         inputSlots = new ArrayList<>(5);
116         outputSlots = new ArrayList<>(1);
117         predecessors = new ArrayList<>(6);
118         successors = new ArrayList<>(6);
119         this.id = id;
120         idString = Integer.toString(id);
121 
122         this.position = new Point(0, 0);
123         this.color = Color.WHITE;
124     }
125 
getId()126     public int getId() {
127         return id;
128     }
129 
setColor(Color color)130     public void setColor(Color color) {
131         this.color = color;
132     }
133 
getColor()134     public Color getColor() {
135         return color;
136     }
137 
getPredecessors()138     public List<Figure> getPredecessors() {
139         return Collections.unmodifiableList(predecessors);
140     }
141 
getPredecessorSet()142     public Set<Figure> getPredecessorSet() {
143         Set<Figure> result = new HashSet<>();
144         for (Figure f : getPredecessors()) {
145             result.add(f);
146         }
147         return Collections.unmodifiableSet(result);
148     }
149 
getSuccessorSet()150     public Set<Figure> getSuccessorSet() {
151         Set<Figure> result = new HashSet<>();
152         for (Figure f : getSuccessors()) {
153             result.add(f);
154         }
155         return Collections.unmodifiableSet(result);
156     }
157 
getSuccessors()158     public List<Figure> getSuccessors() {
159         return Collections.unmodifiableList(successors);
160     }
161 
addPredecessor(Figure f)162     protected void addPredecessor(Figure f) {
163         this.predecessors.add(f);
164     }
165 
addSuccessor(Figure f)166     protected void addSuccessor(Figure f) {
167         this.successors.add(f);
168     }
169 
removePredecessor(Figure f)170     protected void removePredecessor(Figure f) {
171         assert predecessors.contains(f);
172         predecessors.remove(f);
173     }
174 
removeSuccessor(Figure f)175     protected void removeSuccessor(Figure f) {
176         assert successors.contains(f);
177         successors.remove(f);
178     }
179 
getSubgraphs()180     public List<InputGraph> getSubgraphs() {
181         return subgraphs;
182     }
183 
setSubgraphs(List<InputGraph> subgraphs)184     public void setSubgraphs(List<InputGraph> subgraphs) {
185         this.subgraphs = subgraphs;
186     }
187 
188     @Override
setPosition(Point p)189     public void setPosition(Point p) {
190         this.position = p;
191     }
192 
193     @Override
getPosition()194     public Point getPosition() {
195         return position;
196     }
197 
getDiagram()198     public Diagram getDiagram() {
199         return diagram;
200     }
201 
202     @Override
getSource()203     public Source getSource() {
204         return source;
205     }
206 
createInputSlot()207     public InputSlot createInputSlot() {
208         InputSlot slot = new InputSlot(this, -1);
209         inputSlots.add(slot);
210         return slot;
211     }
212 
createInputSlot(int index)213     public InputSlot createInputSlot(int index) {
214         InputSlot slot = new InputSlot(this, index);
215         inputSlots.add(slot);
216         Collections.sort(inputSlots, Slot.slotIndexComparator);
217         return slot;
218     }
219 
removeSlot(Slot s)220     public void removeSlot(Slot s) {
221 
222         assert inputSlots.contains(s) || outputSlots.contains(s);
223 
224         List<Connection> connections = new ArrayList<>(s.getConnections());
225         for (Connection c : connections) {
226             c.remove();
227         }
228 
229         if (inputSlots.contains(s)) {
230             inputSlots.remove(s);
231         } else if (outputSlots.contains(s)) {
232             outputSlots.remove(s);
233         }
234     }
235 
createOutputSlot()236     public OutputSlot createOutputSlot() {
237         OutputSlot slot = new OutputSlot(this, -1);
238         outputSlots.add(slot);
239         return slot;
240     }
241 
createOutputSlot(int index)242     public OutputSlot createOutputSlot(int index) {
243         OutputSlot slot = new OutputSlot(this, index);
244         outputSlots.add(slot);
245         Collections.sort(outputSlots, Slot.slotIndexComparator);
246         return slot;
247     }
248 
getInputSlots()249     public List<InputSlot> getInputSlots() {
250         return Collections.unmodifiableList(inputSlots);
251     }
252 
getSlots()253     public Set<Slot> getSlots() {
254         Set<Slot> result = new HashSet<>();
255         result.addAll(getInputSlots());
256         result.addAll(getOutputSlots());
257         return result;
258     }
259 
getOutputSlots()260     public List<OutputSlot> getOutputSlots() {
261         return Collections.unmodifiableList(outputSlots);
262     }
263 
removeInputSlot(InputSlot s)264     void removeInputSlot(InputSlot s) {
265         s.removeAllConnections();
266         inputSlots.remove(s);
267     }
268 
removeOutputSlot(OutputSlot s)269     void removeOutputSlot(OutputSlot s) {
270         s.removeAllConnections();
271         outputSlots.remove(s);
272     }
273 
getLines()274     public String[] getLines() {
275         if (lines == null) {
276             updateLines();
277         }
278         return lines;
279     }
280 
updateLines()281     public void updateLines() {
282         String[] strings = diagram.getNodeText().split("\n");
283         String[] result = new String[strings.length];
284 
285         for (int i = 0; i < strings.length; i++) {
286             result[i] = resolveString(strings[i], getProperties());
287         }
288 
289         lines = result;
290     }
291 
resolveString(String string, Properties properties)292     public static final String resolveString(String string, Properties properties) {
293 
294         StringBuilder sb = new StringBuilder();
295         boolean inBrackets = false;
296         StringBuilder curIdent = new StringBuilder();
297 
298         for (int i = 0; i < string.length(); i++) {
299             char c = string.charAt(i);
300             if (inBrackets) {
301                 if (c == ']') {
302                     String value = properties.get(curIdent.toString());
303                     if (value == null) {
304                         value = "";
305                     }
306                     sb.append(value);
307                     inBrackets = false;
308                 } else {
309                     curIdent.append(c);
310                 }
311             } else {
312                 if (c == '[') {
313                     inBrackets = true;
314                     curIdent = new StringBuilder();
315                 } else {
316                     sb.append(c);
317                 }
318             }
319         }
320 
321         return sb.toString();
322     }
323 
324     @Override
getSize()325     public Dimension getSize() {
326         if (VERTICAL_LAYOUT) {
327             int width = Math.max(getWidth(), Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1));
328             int height = getHeight() + 2 * Figure.SLOT_WIDTH - 2 * Figure.OVERLAPPING;
329 
330 
331             return new Dimension(width, height);
332         } else {
333             int width = getWidth() + 2 * Figure.SLOT_WIDTH - 2*Figure.OVERLAPPING;
334             int height = Figure.SLOT_WIDTH * (Math.max(inputSlots.size(), outputSlots.size()) + 1);
335             return new Dimension(width, height);
336         }
337     }
338 
339     @Override
toString()340     public String toString() {
341         return idString;
342     }
343 
getCluster()344     public Cluster getCluster() {
345         if (getSource().getSourceNodes().size() == 0) {
346             assert false : "Should never reach here, every figure must have at least one source node!";
347             return null;
348         } else {
349             final InputBlock inputBlock = diagram.getGraph().getBlock(getSource().getSourceNodes().get(0));
350             assert inputBlock != null;
351             Cluster result = diagram.getBlock(inputBlock);
352             assert result != null;
353             return result;
354         }
355     }
356 
357     @Override
isRoot()358     public boolean isRoot() {
359 
360         List<InputNode> sourceNodes = source.getSourceNodes();
361         if (sourceNodes.size() > 0 && sourceNodes.get(0).getProperties().get("name") != null) {
362             return source.getSourceNodes().get(0).getProperties().get("name").equals("Root");
363         } else {
364             return false;
365         }
366     }
367 
368     @Override
compareTo(Vertex f)369     public int compareTo(Vertex f) {
370         return toString().compareTo(f.toString());
371     }
372 
getBounds()373     public Rectangle getBounds() {
374         return new Rectangle(this.getPosition(), new Dimension(this.getWidth(), this.getHeight()));
375     }
376 }
377