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