1 // Copyright (c) 2013 The Chromium 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.
8 * @fileoverview View visualizes TRACE_EVENT events using the
9 * tracing.Timeline component and adds in selection summary and control buttons.
11 tvcm.requireStylesheet('tvcm.ui.common');
12 tvcm.requireStylesheet('tracing.timeline_view');
13 tvcm.requireTemplate('tracing.timeline_view');
15 tvcm.require('tvcm.utils');
16 tvcm.require('tvcm.settings');
17 tvcm.require('tracing.analysis.analysis_view');
18 tvcm.require('tracing.find_control');
19 tvcm.require('tracing.timeline_track_view');
20 tvcm.require('tvcm.ui.dom_helpers');
21 tvcm.require('tvcm.ui.overlay');
22 tvcm.require('tvcm.ui.drag_handle');
24 tvcm.require('tracing.analysis.cpu_slice_view');
25 tvcm.require('tracing.analysis.thread_time_slice_view');
26 tvcm.require('tracing.thread_times_side_panel');
27 tvcm.require('tracing.timeline_view_side_panel');
29 tvcm.exportTo('tracing', function() {
34 * @extends {HTMLUnknownElement}
36 var TimelineView = tvcm.ui.define('x-timeline-view');
38 TimelineView.prototype = {
39 __proto__: HTMLUnknownElement.prototype,
41 decorate: function() {
42 var node = tvcm.instantiateTemplate('#timeline-view-template');
43 this.appendChild(node);
45 this.titleEl_ = this.querySelector('.title');
46 this.leftControlsEl_ = this.querySelector('#left-controls');
47 this.rightControlsEl_ = this.querySelector('#right-controls');
48 this.timelineViewSidePanelContainer_ = this.querySelector(
49 'x-timeline-view-side-panel-container');
50 this.trackViewContainer_ = this.querySelector('track-view-container');
52 tvcm.ui.decorate(this.timelineViewSidePanelContainer_,
53 tracing.TimelineViewSidePanelContainer);
55 this.findCtl_ = new tracing.FindControl();
56 this.findCtl_.controller = new tracing.FindController();
58 this.rightControls.appendChild(this.createMetadataButton_());
59 this.rightControls.appendChild(this.findCtl_);
60 this.rightControls.appendChild(this.createHelpButton_());
62 this.dragEl_ = this.querySelector('x-drag-handle');
63 tvcm.ui.decorate(this.dragEl_, tvcm.ui.DragHandle);
65 this.analysisEl_ = this.querySelector('#analysis');
66 tvcm.ui.decorate(this.analysisEl_, tracing.analysis.AnalysisView);
68 this.appendChild(this.analysisEl_);
69 this.addEventListener('requestSelectionChange',
70 this.onRequestSelectionChange_.bind(this));
73 this.onSelectionChanged_ = this.onSelectionChanged_.bind(this);
74 document.addEventListener('keydown', this.onKeyDown_.bind(this), true);
75 document.addEventListener('keypress', this.onKeypress_.bind(this), true);
77 this.dragEl_.target = this.analysisEl_;
80 createHelpButton_: function() {
81 var node = tvcm.instantiateTemplate('#help-btn-template');
82 var showEl = node.querySelector('.view-help-button');
83 var helpTextEl = node.querySelector('.view-help-text');
85 var dlg = new tvcm.ui.Overlay();
86 dlg.title = 'chrome://tracing Help';
87 dlg.classList.add('view-help-overlay');
88 dlg.appendChild(node);
91 dlg.visible = !dlg.visible;
93 var mod = tvcm.isMac ? 'cmd ' : 'ctrl';
94 var spans = helpTextEl.querySelectorAll('span.mod');
95 for (var i = 0; i < spans.length; i++) {
96 spans[i].textContent = mod;
99 // Stop event so it doesn't trigger new click listener on document.
103 showEl.addEventListener('click', onClick.bind(this));
108 createMetadataButton_: function() {
109 var node = tvcm.instantiateTemplate('#metadata-btn-template');
110 var showEl = node.querySelector('.view-metadata-button');
111 var textEl = node.querySelector('.info-button-text');
113 var dlg = new tvcm.ui.Overlay();
114 dlg.title = 'Metadata for trace';
115 dlg.classList.add('view-metadata-overlay');
116 dlg.appendChild(node);
118 function onClick(e) {
121 var metadataStrings = [];
123 var model = this.model;
124 for (var data in model.metadata) {
125 var meta = model.metadata[data];
126 var name = JSON.stringify(meta.name);
127 var value = JSON.stringify(meta.value, undefined, ' ');
129 metadataStrings.push(name + ': ' + value);
131 textEl.textContent = metadataStrings.join('\n');
136 showEl.addEventListener('click', onClick.bind(this));
138 function updateVisibility() {
139 showEl.style.display =
140 (this.model && this.model.metadata.length) ? '' : 'none';
142 var updateVisibility_ = updateVisibility.bind(this);
144 this.addEventListener('modelChange', updateVisibility_);
150 return this.leftControlsEl_;
153 get rightControls() {
154 return this.rightControlsEl_;
158 return this.titleEl_.textContent.substring(
159 this.titleEl_.textContent.length - 2);
162 set viewTitle(text) {
163 if (text === undefined) {
164 this.titleEl_.textContent = '';
165 this.titleEl_.hidden = true;
168 this.titleEl_.hidden = false;
169 this.titleEl_.textContent = text;
174 return this.trackView_.model;
179 var modelInstanceChanged = model != this.model;
180 var modelValid = model && !model.bounds.isEmpty;
182 // Remove old trackView if the model has completely changed.
183 if (modelInstanceChanged) {
184 this.trackViewContainer_.textContent = '';
185 if (this.trackView_) {
186 this.trackView_.removeEventListener(
187 'selectionChange', this.onSelectionChanged_);
188 this.trackView_.detach();
189 this.trackView_ = undefined;
190 this.findCtl_.controller.trackView = undefined;
192 this.timelineViewSidePanelContainer_.model = undefined;
195 // Create new trackView if needed.
196 if (modelValid && !this.trackView_) {
197 this.trackView_ = new tracing.TimelineTrackView();
198 this.trackView_.focusElement =
199 this.focusElement_ ? this.focusElement_ : this.parentElement;
200 this.trackViewContainer_.appendChild(this.trackView_);
201 this.findCtl_.controller.timeline = this.trackView_;
202 this.trackView_.addEventListener(
203 'selectionChange', this.onSelectionChanged_);
204 this.analysisEl_.clearSelectionHistory();
209 this.trackView_.model = model;
210 this.timelineViewSidePanelContainer_.model = model;
212 tvcm.dispatchSimpleEvent(this, 'modelChange');
214 // Do things that are selection specific
215 if (modelInstanceChanged)
216 this.onSelectionChanged_();
220 return this.trackView_;
225 this.settings_ = new tvcm.Settings();
226 return this.settings_;
230 * Sets the element whose focus state will determine whether
231 * to respond to keybaord input.
233 set focusElement(value) {
234 this.focusElement_ = value;
236 this.trackView_.focusElement = value;
240 * @return {Element} The element whose focused state determines
241 * whether to respond to keyboard inputs.
242 * Defaults to the parent element.
245 if (this.focusElement_)
246 return this.focusElement_;
247 return this.parentElement;
251 * @return {boolean} Whether the current view is attached to the
254 get isAttachedToDocument_() {
256 while (cur.parentNode)
257 cur = cur.parentNode;
258 return cur == this.ownerDocument;
261 get listenToKeys_() {
262 if (!this.isAttachedToDocument_)
264 if (!this.focusElement_)
266 if (this.focusElement.tabIndex >= 0)
267 return document.activeElement == this.focusElement;
271 onKeyDown_: function(e) {
272 if (!this.listenToKeys_)
275 if (e.keyCode === 27) { // ESC
281 onKeypress_: function(e) {
282 if (!this.listenToKeys_)
285 if (e.keyCode === '/'.charCodeAt(0)) {
286 if (this.findCtl_.hasFocus())
289 this.findCtl_.focus();
291 } else if (e.keyCode === '?'.charCodeAt(0)) {
292 this.querySelector('.view-help-button').click();
297 beginFind: function() {
298 if (this.findInProgress_)
300 this.findInProgress_ = true;
301 var dlg = tracing.FindControl();
302 dlg.controller = new tracing.FindController();
303 dlg.controller.trackView = this.trackView;
305 dlg.addEventListener('close', function() {
306 this.findInProgress_ = false;
308 dlg.addEventListener('findNext', function() {
310 dlg.addEventListener('findPrevious', function() {
314 onSelectionChanged_: function(e) {
315 var oldScrollTop = this.trackViewContainer_.scrollTop;
317 var selection = this.trackView_ ?
318 this.trackView_.selectionOfInterest :
319 new tracing.Selection();
320 this.analysisEl_.selection = selection;
321 this.trackViewContainer_.scrollTop = oldScrollTop;
324 onRequestSelectionChange_: function(e) {
325 this.trackView_.selection = e.selection;
331 TimelineView: TimelineView