1 /* 2 * Copyright (c) 1998, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.hotspot.igv.view; 26 27 import com.sun.hotspot.igv.data.*; 28 import com.sun.hotspot.igv.difference.Difference; 29 import com.sun.hotspot.igv.filter.CustomFilter; 30 import com.sun.hotspot.igv.filter.FilterChain; 31 import com.sun.hotspot.igv.graph.Diagram; 32 import com.sun.hotspot.igv.graph.Figure; 33 import com.sun.hotspot.igv.settings.Settings; 34 import com.sun.hotspot.igv.util.RangeSliderModel; 35 import java.awt.Color; 36 import java.util.*; 37 38 /** 39 * 40 * @author Thomas Wuerthinger 41 */ 42 public class DiagramViewModel extends RangeSliderModel implements ChangedListener<RangeSliderModel> { 43 44 // Warning: Update setData method if fields are added 45 private Group group; 46 private ArrayList<InputGraph> graphs; 47 private Set<Integer> hiddenNodes; 48 private Set<Integer> onScreenNodes; 49 private Set<Integer> selectedNodes; 50 private FilterChain filterChain; 51 private FilterChain sequenceFilterChain; 52 private Diagram diagram; 53 private InputGraph inputGraph; 54 private ChangedEvent<DiagramViewModel> groupChangedEvent; 55 private ChangedEvent<DiagramViewModel> diagramChangedEvent; 56 private ChangedEvent<DiagramViewModel> viewChangedEvent; 57 private ChangedEvent<DiagramViewModel> hiddenNodesChangedEvent; 58 private ChangedEvent<DiagramViewModel> viewPropertiesChangedEvent; 59 private boolean showBlocks; 60 private boolean showNodeHull; 61 private boolean hideDuplicates; 62 private ChangedListener<FilterChain> filterChainChangedListener = new ChangedListener<FilterChain>() { 63 64 @Override 65 public void changed(FilterChain source) { 66 diagramChanged(); 67 } 68 }; 69 70 @Override 71 public DiagramViewModel copy() { 72 DiagramViewModel result = new DiagramViewModel(group, filterChain, sequenceFilterChain); 73 result.setData(this); 74 return result; 75 } 76 77 public Group getGroup() { 78 return group; 79 } 80 81 public void setData(DiagramViewModel newModel) { 82 super.setData(newModel); 83 boolean diagramChanged = false; 84 boolean viewChanged = false; 85 boolean viewPropertiesChanged = false; 86 87 boolean groupChanged = (group == newModel.group); 88 this.group = newModel.group; 89 if (groupChanged) { 90 filterGraphs(); 91 } 92 93 diagramChanged |= (filterChain != newModel.filterChain); 94 this.filterChain = newModel.filterChain; 95 diagramChanged |= (sequenceFilterChain != newModel.sequenceFilterChain); 96 this.sequenceFilterChain = newModel.sequenceFilterChain; 97 diagramChanged |= (diagram != newModel.diagram); 98 this.diagram = newModel.diagram; 99 viewChanged |= (hiddenNodes != newModel.hiddenNodes); 100 this.hiddenNodes = newModel.hiddenNodes; 101 viewChanged |= (onScreenNodes != newModel.onScreenNodes); 102 this.onScreenNodes = newModel.onScreenNodes; 103 viewChanged |= (selectedNodes != newModel.selectedNodes); 104 this.selectedNodes = newModel.selectedNodes; 105 viewPropertiesChanged |= (showBlocks != newModel.showBlocks); 106 this.showBlocks = newModel.showBlocks; 107 viewPropertiesChanged |= (showNodeHull != newModel.showNodeHull); 108 this.showNodeHull = newModel.showNodeHull; 109 110 if (groupChanged) { 111 groupChangedEvent.fire(); 112 } 113 114 if (diagramChanged) { 115 diagramChangedEvent.fire(); 116 } 117 if (viewPropertiesChanged) { 118 viewPropertiesChangedEvent.fire(); 119 } 120 if (viewChanged) { 121 viewChangedEvent.fire(); 122 } 123 } 124 125 public boolean getShowBlocks() { 126 return showBlocks; 127 } 128 129 public void setShowBlocks(boolean b) { 130 showBlocks = b; 131 viewPropertiesChangedEvent.fire(); 132 } 133 134 public boolean getShowNodeHull() { 135 return showNodeHull; 136 } 137 138 public void setShowNodeHull(boolean b) { 139 showNodeHull = b; 140 viewPropertiesChangedEvent.fire(); 141 } 142 143 public boolean getHideDuplicates() { 144 return hideDuplicates; 145 } 146 147 public void setHideDuplicates(boolean b) { 148 System.err.println("setHideDuplicates: " + b); 149 hideDuplicates = b; 150 InputGraph currentGraph = getFirstGraph(); 151 if (hideDuplicates) { 152 // Back up to the unhidden equivalent graph 153 int index = graphs.indexOf(currentGraph); 154 while (graphs.get(index).getProperties().get("_isDuplicate") != null) { 155 index--; 156 } 157 currentGraph = graphs.get(index); 158 } 159 filterGraphs(); 160 selectGraph(currentGraph); 161 viewPropertiesChangedEvent.fire(); 162 } 163 164 public DiagramViewModel(Group g, FilterChain filterChain, FilterChain sequenceFilterChain) { 165 super(Arrays.asList("default")); 166 167 this.showBlocks = false; 168 this.showNodeHull = true; 169 this.group = g; 170 filterGraphs(); 171 assert filterChain != null; 172 this.filterChain = filterChain; 173 assert sequenceFilterChain != null; 174 this.sequenceFilterChain = sequenceFilterChain; 175 hiddenNodes = new HashSet<>(); 176 onScreenNodes = new HashSet<>(); 177 selectedNodes = new HashSet<>(); 178 super.getChangedEvent().addListener(this); 179 diagramChangedEvent = new ChangedEvent<>(this); 180 viewChangedEvent = new ChangedEvent<>(this); 181 hiddenNodesChangedEvent = new ChangedEvent<>(this); 182 viewPropertiesChangedEvent = new ChangedEvent<>(this); 183 184 groupChangedEvent = new ChangedEvent<>(this); 185 groupChangedEvent.addListener(groupChangedListener); 186 groupChangedEvent.fire(); 187 188 filterChain.getChangedEvent().addListener(filterChainChangedListener); 189 sequenceFilterChain.getChangedEvent().addListener(filterChainChangedListener); 190 } 191 private final ChangedListener<DiagramViewModel> groupChangedListener = new ChangedListener<DiagramViewModel>() { 192 193 private Group oldGroup; 194 195 @Override 196 public void changed(DiagramViewModel source) { 197 if (oldGroup != null) { 198 oldGroup.getChangedEvent().removeListener(groupContentChangedListener); 199 } 200 group.getChangedEvent().addListener(groupContentChangedListener); 201 oldGroup = group; 202 } 203 }; 204 private final ChangedListener<Group> groupContentChangedListener = new ChangedListener<Group>() { 205 206 @Override 207 public void changed(Group source) { 208 assert source == group; 209 filterGraphs(); 210 setSelectedNodes(selectedNodes); 211 } 212 }; 213 214 public ChangedEvent<DiagramViewModel> getDiagramChangedEvent() { 215 return diagramChangedEvent; 216 } 217 218 public ChangedEvent<DiagramViewModel> getViewChangedEvent() { 219 return viewChangedEvent; 220 } 221 222 public ChangedEvent<DiagramViewModel> getHiddenNodesChangedEvent() { 223 return hiddenNodesChangedEvent; 224 } 225 226 public ChangedEvent<DiagramViewModel> getViewPropertiesChangedEvent() { 227 return viewPropertiesChangedEvent; 228 } 229 230 public Set<Integer> getSelectedNodes() { 231 return selectedNodes; 232 } 233 234 public Set<Integer> getHiddenNodes() { 235 return hiddenNodes; 236 } 237 238 public Set<Integer> getOnScreenNodes() { 239 return onScreenNodes; 240 } 241 242 public void setSelectedNodes(Set<Integer> nodes) { 243 this.selectedNodes = nodes; 244 List<Color> colors = new ArrayList<>(); 245 for (String s : getPositions()) { 246 colors.add(Color.black); 247 } 248 if (nodes.size() >= 1) { 249 for (Integer id : nodes) { 250 if (id < 0) { 251 id = -id; 252 } 253 InputNode last = null; 254 int index = 0; 255 for (InputGraph g : graphs) { 256 Color curColor = colors.get(index); 257 InputNode cur = g.getNode(id); 258 if (cur != null) { 259 if (last == null) { 260 curColor = Color.green; 261 } else { 262 if (last.equals(cur) && last.getProperties().equals(cur.getProperties())) { 263 if (curColor == Color.black) { 264 curColor = Color.white; 265 } 266 } else { 267 if (curColor != Color.green) { 268 curColor = Color.orange; 269 } 270 } 271 } 272 } 273 last = cur; 274 colors.set(index, curColor); 275 index++; 276 } 277 } 278 } 279 setColors(colors); 280 viewChangedEvent.fire(); 281 } 282 283 public void showNot(final Set<Integer> nodes) { 284 setHiddenNodes(nodes); 285 } 286 287 public void showFigures(Collection<Figure> f) { 288 HashSet<Integer> newHiddenNodes = new HashSet<>(getHiddenNodes()); 289 for (Figure fig : f) { 290 newHiddenNodes.removeAll(fig.getSource().getSourceNodesAsSet()); 291 } 292 setHiddenNodes(newHiddenNodes); 293 } 294 295 296 public Set<Figure> getSelectedFigures() { 297 Set<Figure> result = new HashSet<>(); 298 for (Figure f : diagram.getFigures()) { 299 for (InputNode node : f.getSource().getSourceNodes()) { 300 if (getSelectedNodes().contains(node.getId())) { 301 result.add(f); 302 } 303 } 304 } 305 return result; 306 } 307 308 public void showAll(final Collection<Figure> f) { 309 showFigures(f); 310 } 311 312 public void showOnly(final Set<Integer> nodes) { 313 final HashSet<Integer> allNodes = new HashSet<>(getGraphToView().getGroup().getAllNodes()); 314 allNodes.removeAll(nodes); 315 setHiddenNodes(allNodes); 316 } 317 318 public void setHiddenNodes(Set<Integer> nodes) { 319 this.hiddenNodes = nodes; 320 hiddenNodesChangedEvent.fire(); 321 } 322 323 public void setOnScreenNodes(Set<Integer> onScreenNodes) { 324 this.onScreenNodes = onScreenNodes; 325 viewChangedEvent.fire(); 326 } 327 328 public FilterChain getSequenceFilterChain() { 329 return filterChain; 330 } 331 332 public void setSequenceFilterChain(FilterChain chain) { 333 assert chain != null : "sequenceFilterChain must never be null"; 334 sequenceFilterChain.getChangedEvent().removeListener(filterChainChangedListener); 335 sequenceFilterChain = chain; 336 sequenceFilterChain.getChangedEvent().addListener(filterChainChangedListener); 337 diagramChanged(); 338 } 339 340 private void diagramChanged() { 341 // clear diagram 342 diagram = null; 343 getDiagramChangedEvent().fire(); 344 345 } 346 347 public FilterChain getFilterChain() { 348 return filterChain; 349 } 350 351 public void setFilterChain(FilterChain chain) { 352 assert chain != null : "filterChain must never be null"; 353 filterChain.getChangedEvent().removeListener(filterChainChangedListener); 354 filterChain = chain; 355 filterChain.getChangedEvent().addListener(filterChainChangedListener); 356 diagramChanged(); 357 } 358 359 /* 360 * Select the set of graphs to be presented. 361 */ 362 private void filterGraphs() { 363 ArrayList<InputGraph> result = new ArrayList<>(); 364 List<String> positions = new ArrayList<>(); 365 for (InputGraph graph : group.getGraphs()) { 366 String duplicate = graph.getProperties().get("_isDuplicate"); 367 if (duplicate == null || !hideDuplicates) { 368 result.add(graph); 369 positions.add(graph.getName()); 370 } 371 } 372 this.graphs = result; 373 setPositions(positions); 374 } 375 376 public InputGraph getFirstGraph() { 377 if (getFirstPosition() < graphs.size()) { 378 return graphs.get(getFirstPosition()); 379 } 380 return graphs.get(graphs.size() - 1); 381 } 382 383 public InputGraph getSecondGraph() { 384 if (getSecondPosition() < graphs.size()) { 385 return graphs.get(getSecondPosition()); 386 } 387 return getFirstGraph(); 388 } 389 390 public void selectGraph(InputGraph g) { 391 int index = graphs.indexOf(g); 392 if (index == -1 && hideDuplicates) { 393 // A graph was selected that's currently hidden, so unhide and select it. 394 setHideDuplicates(false); 395 index = graphs.indexOf(g); 396 } 397 assert index != -1; 398 setPositions(index, index); 399 } 400 401 public Diagram getDiagramToView() { 402 403 if (diagram == null) { 404 diagram = Diagram.createDiagram(getGraphToView(), Settings.get().get(Settings.NODE_TEXT, Settings.NODE_TEXT_DEFAULT)); 405 getFilterChain().apply(diagram, getSequenceFilterChain()); 406 if (getFirstPosition() != getSecondPosition()) { 407 CustomFilter f = new CustomFilter( 408 "difference", "colorize('state', 'same', white);" 409 + "colorize('state', 'changed', orange);" 410 + "colorize('state', 'new', green);" 411 + "colorize('state', 'deleted', red);"); 412 f.apply(diagram); 413 } 414 } 415 416 return diagram; 417 } 418 419 public InputGraph getGraphToView() { 420 if (inputGraph == null) { 421 if (getFirstGraph() != getSecondGraph()) { 422 inputGraph = Difference.createDiffGraph(getFirstGraph(), getSecondGraph()); 423 } else { 424 inputGraph = getFirstGraph(); 425 } 426 } 427 428 return inputGraph; 429 } 430 431 @Override 432 public void changed(RangeSliderModel source) { 433 inputGraph = null; 434 diagramChanged(); 435 } 436 437 void setSelectedFigures(List<Figure> list) { 438 Set<Integer> newSelectedNodes = new HashSet<>(); 439 for (Figure f : list) { 440 newSelectedNodes.addAll(f.getSource().getSourceNodesAsSet()); 441 } 442 this.setSelectedNodes(newSelectedNodes); 443 } 444 445 void close() { 446 filterChain.getChangedEvent().removeListener(filterChainChangedListener); 447 sequenceFilterChain.getChangedEvent().removeListener(filterChainChangedListener); 448 } 449 }