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 ProfilingView glues the View control to
11 tvcm.require('about_tracing.tracing_ui_client');
12 tvcm.require('tracing.timeline_view');
13 tvcm.require('tvcm.key_event_manager');
14 tvcm.require('tvcm.promise');
15 tvcm.require('tvcm.ui');
16 tvcm.require('tvcm.ui.info_bar');
17 tvcm.require('tvcm.ui.overlay');
19 tvcm.requireTemplate('about_tracing.profiling_view');
20 tvcm.require('about_tracing.features');
22 tvcm.exportTo('about_tracing', function() {
23 function readFile(file) {
24 return new Promise(function(resolver) {
25 var reader = new FileReader();
26 var filename = file.name;
27 reader.onload = function(data) {
28 resolver.resolve(data.target.result);
30 reader.onerror = function(err) {
34 var is_binary = /[.]gz$/.test(filename) || /[.]zip$/.test(filename);
36 reader.readAsArrayBuffer(file);
38 reader.readAsText(file);
45 * @extends {HTMLUnknownElement}
47 var ProfilingView = tvcm.ui.define('x-profiling-view');
49 ProfilingView.prototype = {
50 __proto__: HTMLUnknownElement.prototype,
52 decorate: function(tracingRequestImpl) {
53 this.appendChild(tvcm.instantiateTemplate('#profiling-view-template'));
55 this.timelineView_ = this.querySelector('x-timeline-view');
56 this.infoBarGroup_ = this.querySelector('x-info-bar-group');
58 tvcm.ui.decorate(this.infoBarGroup_, tvcm.ui.InfoBarGroup);
59 tvcm.ui.decorate(this.timelineView_, tracing.TimelineView);
61 // Detach the buttons. We will reattach them to the timeline view.
62 // TODO(nduca): Make <timeline-view> have a <content select="x-buttons">
63 // that pulls in any buttons.
64 var buttons = this.querySelector('x-timeline-view-buttons');
65 buttons.parentElement.removeChild(buttons);
66 this.timelineView_.leftControls.appendChild(buttons);
67 this.initButtons_(buttons);
69 tvcm.KeyEventManager.instance.addListener(
70 'keypress', this.onKeypress_, this);
72 this.initDragAndDrop_();
74 this.tracingRequestImpl_ =
75 tracingRequestImpl || about_tracing.tracingRequest;
76 this.isRecording_ = false;
77 this.isMonitoring_ = false;
78 this.activeTrace_ = undefined;
80 window.onMonitoringStateChanged = function(is_monitoring) {
81 this.onMonitoringStateChanged_(is_monitoring);
84 this.getMonitoringStatus();
87 // Detach all document event listeners. Without this the tests can get
88 // confused as the element may still be listening when the next test runs.
90 this.detachDragAndDrop_();
94 return this.isRecording_;
98 return this.isMonitoring_;
101 set tracingRequestImpl(tracingRequestImpl) {
102 this.tracingRequestImpl_ = tracingRequestImpl;
105 beginRecording: function() {
106 if (this.isRecording_)
107 throw new Error('Already recording');
108 if (this.isMonitoring_)
109 throw new Error('Already monitoring');
110 this.isRecording_ = true;
111 var buttons = this.querySelector('x-timeline-view-buttons');
112 buttons.querySelector('#monitor-checkbox').disabled = true;
113 buttons.querySelector('#monitor-checkbox').checked = false;
114 var resultPromise = about_tracing.beginRecording(
115 this.tracingRequestImpl_);
118 this.isRecording_ = false;
119 buttons.querySelector('#monitor-checkbox').disabled = false;
120 this.setActiveTrace('trace.json', data, false);
123 this.isRecording_ = false;
124 buttons.querySelector('#monitor-checkbox').disabled = false;
125 if (err instanceof about_tracing.UserCancelledError)
127 tvcm.ui.Overlay.showError('Error while recording', err);
129 return resultPromise;
132 beginMonitoring: function() {
133 if (this.isRecording_)
134 throw new Error('Already recording');
135 if (this.isMonitoring_)
136 throw new Error('Already monitoring');
137 var buttons = this.querySelector('x-timeline-view-buttons');
139 about_tracing.beginMonitoring(this.tracingRequestImpl_);
144 if (err instanceof about_tracing.UserCancelledError)
146 tvcm.ui.Overlay.showError('Error while monitoring', err);
148 return resultPromise;
151 endMonitoring: function() {
152 if (this.isRecording_)
153 throw new Error('Already recording');
154 if (!this.isMonitoring_)
155 throw new Error('Monitoring is disabled');
156 var buttons = this.querySelector('x-timeline-view-buttons');
158 about_tracing.endMonitoring(this.tracingRequestImpl_);
163 if (err instanceof about_tracing.UserCancelledError)
165 tvcm.ui.Overlay.showError('Error while monitoring', err);
167 return resultPromise;
170 captureMonitoring: function() {
171 if (!this.isMonitoring_)
172 throw new Error('Monitoring is disabled');
174 about_tracing.captureMonitoring(this.tracingRequestImpl_);
177 this.setActiveTrace('trace.json', data, true);
180 if (err instanceof about_tracing.UserCancelledError)
182 tvcm.ui.Overlay.showError('Error while monitoring', err);
184 return resultPromise;
187 getMonitoringStatus: function() {
189 about_tracing.getMonitoringStatus(this.tracingRequestImpl_);
191 function(isMonitoring, categoryFilter, useSystemTracing,
192 useContinuousTracing, useSampling) {
193 this.onMonitoringStateChanged_(isMonitoring);
196 if (err instanceof about_tracing.UserCancelledError)
198 tvcm.ui.Overlay.showError('Error while updating tracing states',
201 return resultPromise;
204 onMonitoringStateChanged_: function(is_monitoring) {
205 this.isMonitoring_ = is_monitoring;
206 var buttons = this.querySelector('x-timeline-view-buttons');
207 buttons.querySelector('#record-button').disabled = is_monitoring;
208 buttons.querySelector('#capture-button').disabled = !is_monitoring;
209 buttons.querySelector('#monitor-checkbox').checked = is_monitoring;
212 onKeypress_: function(event) {
213 if (document.activeElement.nodeName === 'INPUT')
216 if (!this.isRecording &&
217 event.keyCode === 'r'.charCodeAt(0)) {
218 this.beginRecording();
219 event.preventDefault();
220 event.stopPropagation();
226 return this.timelineView_;
229 ///////////////////////////////////////////////////////////////////////////
231 clearActiveTrace: function() {
232 this.saveButton_.disabled = true;
233 this.activeTrace_ = undefined;
236 setActiveTrace: function(filename, data) {
237 this.activeTrace_ = {
242 this.infoBarGroup_.clearMessages();
243 this.saveButton_.disabled = false;
244 this.timelineView_.viewTitle = filename;
246 var m = new tracing.TraceModel();
247 var p = m.importTracesWithProgressDialog([data], true);
250 this.timelineView_.model = m;
253 tvcm.ui.Overlay.showError('While importing: ', err);
257 ///////////////////////////////////////////////////////////////////////////
259 initButtons_: function(buttons) {
260 buttons.querySelector('#record-button').addEventListener(
261 'click', function() {
262 this.beginRecording();
265 buttons.querySelector('#monitor-checkbox').addEventListener(
266 'click', function() {
267 if (this.isMonitoring_)
268 this.endMonitoring();
270 this.beginMonitoring();
273 buttons.querySelector('#capture-button').addEventListener(
274 'click', function() {
275 this.captureMonitoring();
277 buttons.querySelector('#capture-button').disabled = true;
279 buttons.querySelector('#load-button').addEventListener(
280 'click', this.onLoadClicked_.bind(this));
282 this.saveButton_ = buttons.querySelector('#save-button');
283 this.saveButton_.addEventListener('click',
284 this.onSaveClicked_.bind(this));
285 this.saveButton_.disabled = true;
288 onSaveClicked_: function() {
289 // Create a blob URL from the binary array.
290 var blob = new Blob([this.activeTrace_.data],
291 {type: 'application/octet-binary'});
292 var blobUrl = window.webkitURL.createObjectURL(blob);
294 // Create a link and click on it. BEST API EVAR!
295 var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
297 link.download = this.activeTrace_.filename;
301 onLoadClicked_: function() {
302 var inputElement = document.createElement('input');
303 inputElement.type = 'file';
304 inputElement.multiple = false;
306 var changeFired = false;
307 inputElement.addEventListener(
314 var file = inputElement.files[0];
317 this.setActiveTrace(file.name, data);
320 tvcm.ui.Overlay.showError('Error while loading file: ' + err);
322 }.bind(this), false);
323 inputElement.click();
326 ///////////////////////////////////////////////////////////////////////////
328 initDragAndDrop_: function() {
329 this.dropHandler_ = this.dropHandler_.bind(this);
330 this.ignoreDragEvent_ = this.ignoreDragEvent_.bind(this);
331 document.addEventListener('dragstart', this.ignoreDragEvent_, false);
332 document.addEventListener('dragend', this.ignoreDragEvent_, false);
333 document.addEventListener('dragenter', this.ignoreDragEvent_, false);
334 document.addEventListener('dragleave', this.ignoreDragEvent_, false);
335 document.addEventListener('dragover', this.ignoreDragEvent_, false);
336 document.addEventListener('drop', this.dropHandler_, false);
339 detachDragAndDrop_: function() {
340 document.removeEventListener('dragstart', this.ignoreDragEvent_);
341 document.removeEventListener('dragend', this.ignoreDragEvent_);
342 document.removeEventListener('dragenter', this.ignoreDragEvent_);
343 document.removeEventListener('dragleave', this.ignoreDragEvent_);
344 document.removeEventListener('dragover', this.ignoreDragEvent_);
345 document.removeEventListener('drop', this.dropHandler_);
348 ignoreDragEvent_: function(e) {
353 dropHandler_: function(e) {
354 if (this.isAnyDialogUp_)
360 var files = e.dataTransfer.files;
361 if (files.length !== 1) {
362 tvcm.ui.Overlay.showError('1 file supported at a time.');
366 readFile(files[0]).then(
368 this.setActiveTrace(files[0].name, data);
371 tvcm.ui.Overlay.showError('Error while loading file: ' + err);
378 ProfilingView: ProfilingView