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 }