1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/iteration_helpers.html">
9<link rel="import" href="/tracing/model/event_set.html">
10<link rel="import" href="/tracing/ui/analysis/alert_sub_view.html">
11<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html">
12<link rel="import"
13    href="/tracing/ui/analysis/container_memory_dump_sub_view.html">
14<link rel="import" href="/tracing/ui/analysis/counter_sample_sub_view.html">
15<link rel="import" href="/tracing/ui/analysis/layout_tree_sub_view.html">
16<link rel="import" href="/tracing/ui/analysis/multi_async_slice_sub_view.html">
17<link rel="import" href="/tracing/ui/analysis/multi_cpu_slice_sub_view.html">
18<link rel="import" href="/tracing/ui/analysis/multi_flow_event_sub_view.html">
19<link rel="import" href="/tracing/ui/analysis/multi_frame_sub_view.html">
20<link rel="import"
21      href="/tracing/ui/analysis/multi_instant_event_sub_view.html">
22<link rel="import" href="/tracing/ui/analysis/multi_object_sub_view.html">
23<link rel="import" href="/tracing/ui/analysis/multi_power_sample_sub_view.html">
24<link rel="import" href="/tracing/ui/analysis/multi_sample_sub_view.html">
25<link rel="import" href="/tracing/ui/analysis/multi_thread_slice_sub_view.html">
26<link rel="import"
27      href="/tracing/ui/analysis/multi_thread_time_slice_sub_view.html">
28<link rel="import"
29    href="/tracing/ui/analysis/multi_user_expectation_sub_view.html">
30<link rel="import" href="/tracing/ui/analysis/single_async_slice_sub_view.html">
31<link rel="import" href="/tracing/ui/analysis/single_cpu_slice_sub_view.html">
32<link rel="import" href="/tracing/ui/analysis/single_flow_event_sub_view.html">
33<link rel="import" href="/tracing/ui/analysis/single_frame_sub_view.html">
34<link rel="import"
35      href="/tracing/ui/analysis/single_instant_event_sub_view.html">
36<link rel="import"
37      href="/tracing/ui/analysis/single_object_instance_sub_view.html">
38<link rel="import"
39      href="/tracing/ui/analysis/single_object_snapshot_sub_view.html">
40<link rel="import"
41      href="/tracing/ui/analysis/single_power_sample_sub_view.html">
42<link rel="import" href="/tracing/ui/analysis/single_sample_sub_view.html">
43<link rel="import"
44      href="/tracing/ui/analysis/single_thread_slice_sub_view.html">
45<link rel="import"
46      href="/tracing/ui/analysis/single_thread_time_slice_sub_view.html">
47<link rel="import"
48    href="/tracing/ui/analysis/single_user_expectation_sub_view.html">
49<link rel="import" href="/tracing/ui/base/polymer_utils.html">
50<link rel="import" href="/tracing/ui/base/tab_view.html">
51
52<!--
53@fileoverview A component used to display an analysis of a selection,
54using custom elements specialized for different event types.
55-->
56<polymer-element name="tr-ui-a-analysis-view">
57  <template>
58    <style>
59      :host {
60        background-color: white;
61        display: flex;
62        flex-direction: column;
63        height: 275px;
64        overflow: auto;
65      }
66
67      :host(.tall-mode) {
68        height: 525px;
69      }
70
71      ::content > * {
72        flex: 1 0 auto;
73      }
74    </style>
75    <content></content>
76  </template>
77  <script>
78  'use strict';
79  (function() {
80    var EventRegistry = tr.model.EventRegistry;
81
82    Polymer({
83      ready: function() {
84        this.tabView_ = document.createElement('tr-ui-a-tab-view');
85        this.tabView_.style.flex = '1 1 auto';
86        this.appendChild(this.tabView_);
87        this.brushingStateController_ = undefined;
88        this.onSelectedTabChange_ = this.onSelectedTabChange_.bind(this);
89        this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
90
91        this.lastSeenSelection_ = new tr.model.EventSet();
92      },
93
94      set tallMode(value) {
95        if (value)
96          this.classList.add('tall-mode');
97        else
98          this.classList.remove('tall-mode');
99      },
100
101      get tallMode() {
102        return this.classList.contains('tall-mode');
103      },
104
105      get tabView() {
106        return this.tabView_;
107      },
108
109      get brushingStateController() {
110        return this.brushingStateController_;
111      },
112
113      set brushingStateController(brushingStateController) {
114        if (this.brushingStateController) {
115          this.brushingStateController_.removeEventListener(
116              'change', this.onSelectionChanged_);
117        }
118        this.brushingStateController_ = brushingStateController;
119        if (this.brushingStateController) {
120          this.brushingStateController_.addEventListener(
121              'change', this.onSelectionChanged_);
122        }
123        this.onSelectionChanged_();
124      },
125
126      get selection() {
127        return this.brushingStateController_.selection;
128      },
129
130      onSelectionChanged_: function(e) {
131        var selection = this.brushingStateController_.selection;
132
133        var selectionHasSameValue = this.lastSeenSelection_.equals(selection);
134        this.lastSeenSelection_ = selection;
135        if (selectionHasSameValue)
136          return;
137
138        var lastSelectedTabTagName;
139        var lastSelectedTabTypeName;
140        if (this.tabView_.selectedTab) {
141          lastSelectedTabTagName = this.tabView_.selectedTab.tagName;
142          lastSelectedTabTypeName = this.tabView_.selectedTab._eventTypeName;
143        }
144
145        this.tallMode = false;
146
147        var previouslySelectedTab = this.tabView_.selectedTab;
148        this.tabView_.removeEventListener(
149          'selected-tab-change', this.onSelectedTabChange_);
150
151        var previousSubViews = {};
152        for (var i = 0; i < this.tabView_.children.length; i++) {
153          var previousSubView = this.tabView_.children[i];
154          previousSubViews[previousSubView._eventTypeName] = previousSubView;
155        }
156
157        this.tabView_.saveTabStates();
158        this.tabView_.textContent = '';
159        if (selection.length == 0) {
160          this.tabView_.tabStripHeadingText = 'Nothing selected. Tap stuff.';
161        } else if (selection.length == 1) {
162          this.tabView_.tabStripHeadingText = '1 item selected: ';
163        } else {
164          this.tabView_.tabStripHeadingText = selection.length +
165              ' items selected: ';
166        }
167
168        var eventsByBaseTypeName = selection.getEventsOrganizedByBaseType(true);
169
170        var numBaseTypesToAnalyze = tr.b.dictionaryLength(eventsByBaseTypeName);
171        for (var eventTypeName in eventsByBaseTypeName) {
172          var subSelection = eventsByBaseTypeName[eventTypeName];
173          var subView = this.createSubViewForSelection_(
174            eventTypeName, subSelection, previousSubViews[eventTypeName]);
175          // Store the eventTypeName for future tab restoration.
176          subView._eventTypeName = eventTypeName;
177          this.tabView_.appendChild(subView);
178
179          subView.selection = subSelection;
180        }
181
182        // Restore the tab type that was previously selected. First try by tag
183        // name.
184        var tab;
185        if (lastSelectedTabTagName)
186          tab = this.tabView_.querySelector(lastSelectedTabTagName);
187
188        // If that fails, look for a tab with that typeName.
189        if (!tab && lastSelectedTabTypeName) {
190          var tab = tr.b.findFirstInArray(
191              this.tabView_.children, function(tab) {
192            return tab._eventTypeName === lastSelectedTabTypeName;
193          });
194        }
195        // If all else fails, pick the first tab.
196        if (!tab)
197          tab = this.tabView_.firstChild;
198
199        this.tabView_.selectedTab = tab;
200        this.onSelectedTabChange_();
201
202        this.tabView_.addEventListener(
203          'selected-tab-change', this.onSelectedTabChange_);
204      },
205
206      createSubViewForSelection_: function(eventTypeName, subSelection,
207          previousSubView) {
208        // Find.
209        var eventTypeInfo = EventRegistry.getEventTypeInfoByTypeName(
210            eventTypeName);
211        var singleMode = subSelection.length == 1;
212        var tagName;
213        if (subSelection.length === 1)
214          tagName = eventTypeInfo.metadata.singleViewElementName;
215        else
216          tagName = eventTypeInfo.metadata.multiViewElementName;
217
218        if (!tr.ui.b.getPolymerElementNamed(tagName))
219          throw new Error('Element not registered: ' + tagName);
220
221        // Create if necessary.
222        var subView;
223        if (previousSubView &&
224            previousSubView.tagName === tagName.toUpperCase())
225          subView = previousSubView;
226        else
227          subView = document.createElement(tagName);
228
229        // Set label.
230        var camelLabel;
231        if (subSelection.length === 1)
232          camelLabel = EventRegistry.getUserFriendlySingularName(eventTypeName);
233        else
234          camelLabel = EventRegistry.getUserFriendlyPluralName(eventTypeName);
235        subView.tabLabel = camelLabel + ' (' + subSelection.length + ')';
236
237        return subView;
238      },
239
240      onSelectedTabChange_: function() {
241        var brushingStateController = this.brushingStateController_;
242        if (this.tabView_.selectedTab) {
243          var selectedTab = this.tabView_.selectedTab;
244          this.tallMode = selectedTab.requiresTallView;
245          if (brushingStateController) {
246            var rlth = selectedTab.relatedEventsToHighlight;
247            brushingStateController.changeAnalysisViewRelatedEvents(rlth);
248          }
249        } else {
250          this.tallMode = false;
251          if (brushingStateController)
252            brushingStateController.changeAnalysisViewRelatedEvents(undefined);
253        }
254      }
255    });
256  })();
257  </script>
258</polymer-element>
259