• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import { GraphView } from "../src/graph-view";
6import { ScheduleView } from "../src/schedule-view";
7import { SequenceView } from "../src/sequence-view";
8import { SourceResolver } from "../src/source-resolver";
9import { SelectionBroker } from "../src/selection-broker";
10import { View, PhaseView } from "../src/view";
11import { GNode } from "./node";
12
13const multiviewID = "multiview";
14
15const toolboxHTML = `
16<div class="graph-toolbox">
17  <select id="phase-select">
18    <option disabled selected>(please open a file)</option>
19  </select>
20  <input id="search-input" type="text" title="search nodes for regex" alt="search node for regex" class="search-input"
21    placeholder="find with regexp&hellip;">
22  <label><input id="search-only-visible" type="checkbox" name="instruction-address" alt="Apply search to visible nodes only">only visible</label>
23</div>`;
24
25export class GraphMultiView extends View {
26  sourceResolver: SourceResolver;
27  selectionBroker: SelectionBroker;
28  graph: GraphView;
29  schedule: ScheduleView;
30  sequence: SequenceView;
31  selectMenu: HTMLSelectElement;
32  currentPhaseView: PhaseView;
33
34  createViewElement() {
35    const pane = document.createElement("div");
36    pane.setAttribute("id", multiviewID);
37    pane.setAttribute("tabindex", "1");
38    pane.className = "viewpane";
39    return pane;
40  }
41
42  hide() {
43    this.hideCurrentPhase();
44    super.hide();
45  }
46
47  constructor(id, selectionBroker, sourceResolver) {
48    super(id);
49    const view = this;
50    view.sourceResolver = sourceResolver;
51    view.selectionBroker = selectionBroker;
52    const toolbox = document.createElement("div");
53    toolbox.className = "toolbox-anchor";
54    toolbox.innerHTML = toolboxHTML;
55    view.divNode.appendChild(toolbox);
56    const searchInput = toolbox.querySelector("#search-input") as HTMLInputElement;
57    const onlyVisibleCheckbox = toolbox.querySelector("#search-only-visible") as HTMLInputElement;
58    searchInput.addEventListener("keyup", e => {
59      if (!view.currentPhaseView) return;
60      view.currentPhaseView.searchInputAction(searchInput, e, onlyVisibleCheckbox.checked);
61    });
62    view.divNode.addEventListener("keyup", (e: KeyboardEvent) => {
63      if (e.keyCode == 191) { // keyCode == '/'
64        searchInput.focus();
65      } else if (e.keyCode == 78) { // keyCode == 'n'
66        view.displayNextGraphPhase();
67      } else if (e.keyCode == 66) { // keyCode == 'b'
68        view.displayPreviousGraphPhase();
69      }
70    });
71    searchInput.setAttribute("value", window.sessionStorage.getItem("lastSearch") || "");
72    this.graph = new GraphView(this.divNode, selectionBroker, view.displayPhaseByName.bind(this),
73      toolbox.querySelector(".graph-toolbox"));
74    this.schedule = new ScheduleView(this.divNode, selectionBroker);
75    this.sequence = new SequenceView(this.divNode, selectionBroker);
76    this.selectMenu = toolbox.querySelector("#phase-select") as HTMLSelectElement;
77  }
78
79  initializeSelect() {
80    const view = this;
81    view.selectMenu.innerHTML = "";
82    view.sourceResolver.forEachPhase(phase => {
83      const optionElement = document.createElement("option");
84      let maxNodeId = "";
85      if (phase.type == "graph" && phase.highestNodeId != 0) {
86        maxNodeId = ` ${phase.highestNodeId}`;
87      }
88      optionElement.text = `${phase.name}${maxNodeId}`;
89      view.selectMenu.add(optionElement);
90    });
91    this.selectMenu.onchange = function (this: HTMLSelectElement) {
92      const phaseIndex = this.selectedIndex;
93      window.sessionStorage.setItem("lastSelectedPhase", phaseIndex.toString());
94      view.displayPhase(view.sourceResolver.getPhase(phaseIndex));
95    };
96  }
97
98  show() {
99    // Insert before is used so that the display is inserted before the
100    // resizer for the RangeView.
101    this.container.insertBefore(this.divNode, this.container.firstChild);
102    this.initializeSelect();
103    const lastPhaseIndex = +window.sessionStorage.getItem("lastSelectedPhase");
104    const initialPhaseIndex = this.sourceResolver.repairPhaseId(lastPhaseIndex);
105    this.selectMenu.selectedIndex = initialPhaseIndex;
106    this.displayPhase(this.sourceResolver.getPhase(initialPhaseIndex));
107  }
108
109  displayPhase(phase, selection?: Map<string, GNode>) {
110    if (phase.type == "graph") {
111      this.displayPhaseView(this.graph, phase, selection);
112    } else if (phase.type == "schedule") {
113      this.displayPhaseView(this.schedule, phase, selection);
114    } else if (phase.type == "sequence") {
115      this.displayPhaseView(this.sequence, phase, selection);
116    }
117  }
118
119  displayPhaseView(view: PhaseView, data, selection?: Map<string, GNode>) {
120    const rememberedSelection = selection ? selection : this.hideCurrentPhase();
121    view.initializeContent(data, rememberedSelection);
122    this.currentPhaseView = view;
123  }
124
125  displayPhaseByName(phaseName, selection?: Map<string, GNode>) {
126    const phaseId = this.sourceResolver.getPhaseIdByName(phaseName);
127    this.selectMenu.selectedIndex = phaseId;
128    this.displayPhase(this.sourceResolver.getPhase(phaseId), selection);
129  }
130
131  displayNextGraphPhase() {
132    let nextPhaseIndex = this.selectMenu.selectedIndex + 1;
133    while (nextPhaseIndex < this.sourceResolver.phases.length) {
134      const nextPhase = this.sourceResolver.getPhase(nextPhaseIndex);
135      if (nextPhase.type == "graph") {
136        this.selectMenu.selectedIndex = nextPhaseIndex;
137        window.sessionStorage.setItem("lastSelectedPhase", nextPhaseIndex.toString());
138        this.displayPhase(nextPhase);
139        break;
140      }
141      nextPhaseIndex += 1;
142    }
143  }
144
145  displayPreviousGraphPhase() {
146    let previousPhaseIndex = this.selectMenu.selectedIndex - 1;
147    while (previousPhaseIndex >= 0) {
148      const previousPhase = this.sourceResolver.getPhase(previousPhaseIndex);
149      if (previousPhase.type == "graph") {
150        this.selectMenu.selectedIndex = previousPhaseIndex;
151        window.sessionStorage.setItem("lastSelectedPhase", previousPhaseIndex.toString());
152        this.displayPhase(previousPhase);
153        break;
154      }
155      previousPhaseIndex -= 1;
156    }
157  }
158
159  hideCurrentPhase() {
160    let rememberedSelection = null;
161    if (this.currentPhaseView != null) {
162      rememberedSelection = this.currentPhaseView.detachSelection();
163      this.currentPhaseView.hide();
164      this.currentPhaseView = null;
165    }
166    return rememberedSelection;
167  }
168
169  onresize() {
170    if (this.currentPhaseView) this.currentPhaseView.onresize();
171  }
172
173  detachSelection() {
174    return null;
175  }
176}
177