1<!DOCTYPE html> 2<!-- 3Copyright (c) 2013 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/settings.html"> 9<link rel="import" href="/tracing/base/utils.html"> 10<link rel="import" href="/tracing/core/scripting_controller.html"> 11<link rel="import" href="/tracing/metrics/all_metrics.html"> 12<link rel="import" href="/tracing/ui/analysis/analysis_view.html"> 13<link rel="import" href="/tracing/ui/base/dom_helpers.html"> 14<link rel="import" href="/tracing/ui/base/drag_handle.html"> 15<link rel="import" href="/tracing/ui/base/dropdown.html"> 16<link rel="import" href="/tracing/ui/base/favicons.html"> 17<link rel="import" href="/tracing/ui/base/hotkey_controller.html"> 18<link rel="import" href="/tracing/ui/base/info_bar_group.html"> 19<link rel="import" href="/tracing/ui/base/overlay.html"> 20<link rel="import" href="/tracing/ui/base/toolbar_button.html"> 21<link rel="import" href="/tracing/ui/base/utils.html"> 22<link rel="import" href="/tracing/ui/brushing_state_controller.html"> 23<link rel="import" href="/tracing/ui/find_control.html"> 24<link rel="import" href="/tracing/ui/find_controller.html"> 25<link rel="import" href="/tracing/ui/scripting_control.html"> 26<link rel="import" href="/tracing/ui/side_panel/side_panel_container.html"> 27<link rel="import" href="/tracing/ui/timeline_track_view.html"> 28<link rel="import" href="/tracing/ui/timeline_view_help_overlay.html"> 29<link rel="import" href="/tracing/ui/timeline_view_metadata_overlay.html"> 30<link rel="import" href="/tracing/value/ui/preferred_display_unit.html"> 31 32<polymer-element name='tr-ui-timeline-view'> 33 <template> 34 <style> 35 :host { 36 flex-direction: column; 37 cursor: default; 38 display: flex; 39 font-family: sans-serif; 40 padding: 0; 41 } 42 43 #control { 44 background-color: #e6e6e6; 45 background-image: -webkit-gradient(linear, 0 0, 0 100%, 46 from(#E5E5E5), to(#D1D1D1)); 47 flex: 0 0 auto; 48 overflow-x: auto; 49 } 50 51 #control::-webkit-scrollbar { height: 0px; } 52 53 #control > #bar { 54 font-size: 12px; 55 display: flex; 56 flex-direction: row; 57 margin: 1px; 58 } 59 60 #control > #bar > #title { 61 display: flex; 62 align-items: center; 63 padding-left: 8px; 64 padding-right: 8px; 65 flex: 1 1 auto; 66 } 67 68 #control > #bar > #left_controls, 69 #control > #bar > #right_controls { 70 display: flex; 71 flex-direction: row; 72 align-items: stretch; 73 } 74 75 #control > #bar > #left_controls > * { margin-right: 2px; } 76 #control > #bar > #right_controls > * { margin-left: 2px; } 77 #control > #collapsing_controls { display: flex; } 78 79 middle-container { 80 flex: 1 1 auto; 81 flex-direction: row; 82 border-bottom: 1px solid #8e8e8e; 83 display: flex; 84 min-height: 0; 85 } 86 87 middle-container ::content track-view-container { 88 flex: 1 1 auto; 89 display: flex; 90 min-height: 0; 91 min-width: 0; 92 } 93 94 middle-container ::content track-view-container > * { flex: 1 1 auto; } 95 middle-container > x-timeline-view-side-panel-container { flex: 0 0 auto; } 96 tr-ui-b-drag-handle { flex: 0 0 auto; } 97 tr-ui-a-analysis-view { flex: 0 0 auto; } 98 </style> 99 100 <tv-ui-b-hotkey-controller id="hkc"></tv-ui-b-hotkey-controller> 101 <div id="control"> 102 <div id="bar"> 103 <div id="left_controls"></div> 104 <div id="title">^_^</div> 105 <div id="right_controls"> 106 <tr-ui-b-toolbar-button id="view_metadata_button"> 107 M 108 </tr-ui-b-toolbar-button> 109 <tr-ui-b-dropdown id="view_options_dropdown"></tr-ui-b-dropdown> 110 <tr-ui-find-control id="view_find_control"></tr-ui-find-control> 111 <tr-ui-b-toolbar-button id="view_console_button"> 112 » 113 </tr-ui-b-toolbar-button> 114 <tr-ui-b-toolbar-button id="view_help_button"> 115 ? 116 </tr-ui-b-toolbar-button> 117 </div> 118 </div> 119 <div id="collapsing_controls"></div> 120 <tr-ui-b-info-bar-group id="import-warnings"> 121 </tr-ui-b-info-bar-group> 122 </div> 123 <middle-container> 124 <content></content> 125 126 <tr-ui-side-panel-container id="side_panel_container"> 127 </tr-ui-side-panel-container> 128 </middle-container> 129 <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle> 130 <tr-ui-a-analysis-view id="analysis"></tr-ui-a-analysis-view> 131 132 <tr-v-ui-preferred-display-unit id="display_unit"> 133 </tr-v-ui-preferred-display-unit> 134 </template> 135 136 <script> 137 'use strict'; 138 139 Polymer({ 140 ready: function() { 141 this.tabIndex = 0; // Let the timeline able to receive key events. 142 143 this.titleEl_ = this.$.title; 144 this.leftControlsEl_ = this.$.left_controls; 145 this.rightControlsEl_ = this.$.right_controls; 146 this.collapsingControlsEl_ = this.$.collapsing_controls; 147 this.sidePanelContainer_ = this.$.side_panel_container; 148 149 this.brushingStateController_ = new tr.c.BrushingStateController(this); 150 151 this.findCtl_ = this.$.view_find_control; 152 this.findCtl_.controller = new tr.ui.FindController( 153 this.brushingStateController_); 154 155 this.scriptingCtl_ = document.createElement('tr-ui-scripting-control'); 156 this.scriptingCtl_.controller = new tr.c.ScriptingController( 157 this.brushingStateController_); 158 159 this.sidePanelContainer_.brushingStateController = 160 this.brushingStateController_; 161 162 if (window.tr.metrics && window.tr.metrics.sh && 163 window.tr.metrics.sh.SystemHealthMetric) { 164 this.railScoreSpan_ = document.createElement( 165 'tr-metrics-ui-sh-system-health-span'); 166 this.rightControls.appendChild(this.railScoreSpan_); 167 } else { 168 this.railScoreSpan_ = undefined; 169 } 170 171 this.optionsDropdown_ = this.$.view_options_dropdown; 172 this.optionsDropdown_.iconElement.textContent = 'View Options'; 173 174 this.showFlowEvents_ = false; 175 this.optionsDropdown_.appendChild(tr.ui.b.createCheckBox( 176 this, 'showFlowEvents', 177 'tr.ui.TimelineView.showFlowEvents', false, 178 'Flow events')); 179 this.highlightVSync_ = false; 180 this.highlightVSyncCheckbox_ = tr.ui.b.createCheckBox( 181 this, 'highlightVSync', 182 'tr.ui.TimelineView.highlightVSync', false, 183 'Highlight VSync'); 184 this.optionsDropdown_.appendChild(this.highlightVSyncCheckbox_); 185 186 this.initMetadataButton_(); 187 this.initConsoleButton_(); 188 this.initHelpButton_(); 189 190 this.collapsingControls.appendChild(this.scriptingCtl_); 191 192 this.dragEl_ = this.$.drag_handle; 193 194 this.analysisEl_ = this.$.analysis; 195 this.analysisEl_.brushingStateController = this.brushingStateController_; 196 197 this.addEventListener( 198 'requestSelectionChange', 199 function(e) { 200 var sc = this.brushingStateController_; 201 sc.changeSelectionFromRequestSelectionChangeEvent(e.selection); 202 }.bind(this)); 203 204 // Bookkeeping. 205 this.onViewportChanged_ = this.onViewportChanged_.bind(this); 206 this.bindKeyListeners_(); 207 208 this.dragEl_.target = this.analysisEl_; 209 }, 210 211 domReady: function() { 212 this.trackViewContainer_ = this.querySelector('#track_view_container'); 213 }, 214 215 get globalMode() { 216 return this.hotkeyController.globalMode; 217 }, 218 219 set globalMode(globalMode) { 220 globalMode = !!globalMode; 221 this.brushingStateController_.historyEnabled = globalMode; 222 this.hotkeyController.globalMode = globalMode; 223 }, 224 225 get hotkeyController() { 226 return this.$.hkc; 227 }, 228 229 updateDocumentFavicon: function() { 230 var hue; 231 if (!this.model) 232 hue = 'blue'; 233 else 234 hue = this.model.faviconHue; 235 236 var faviconData = tr.ui.b.FaviconsByHue[hue]; 237 if (faviconData === undefined) 238 faviconData = tr.ui.b.FaviconsByHue['blue']; 239 240 // Find link if its there 241 var link = document.head.querySelector('link[rel="shortcut icon"]'); 242 if (!link) { 243 link = document.createElement('link'); 244 link.rel = 'shortcut icon'; 245 document.head.appendChild(link); 246 } 247 link.href = faviconData; 248 }, 249 250 get showFlowEvents() { 251 return this.showFlowEvents_; 252 }, 253 254 set showFlowEvents(showFlowEvents) { 255 this.showFlowEvents_ = showFlowEvents; 256 if (!this.trackView_) 257 return; 258 this.trackView_.viewport.showFlowEvents = showFlowEvents; 259 }, 260 261 get highlightVSync() { 262 return this.highlightVSync_; 263 }, 264 265 set highlightVSync(highlightVSync) { 266 this.highlightVSync_ = highlightVSync; 267 if (!this.trackView_) 268 return; 269 this.trackView_.viewport.highlightVSync = highlightVSync; 270 }, 271 272 initHelpButton_: function() { 273 var helpButtonEl = this.$.view_help_button; 274 275 function onClick(e) { 276 var dlg = new tr.ui.b.Overlay(); 277 dlg.title = 'Chrome Tracing Help'; 278 dlg.appendChild( 279 document.createElement('tr-ui-timeline-view-help-overlay')); 280 dlg.visible = true; 281 282 // Stop event so it doesn't trigger new click listener on document. 283 e.stopPropagation(); 284 } 285 helpButtonEl.addEventListener('click', onClick.bind(this)); 286 }, 287 288 initConsoleButton_: function() { 289 var toggleEl = this.$.view_console_button; 290 291 function onClick(e) { 292 this.scriptingCtl_.toggleVisibility(); 293 e.stopPropagation(); 294 return false; 295 } 296 toggleEl.addEventListener('click', onClick.bind(this)); 297 }, 298 299 initMetadataButton_: function() { 300 var showEl = this.$.view_metadata_button; 301 302 function onClick(e) { 303 var dlg = new tr.ui.b.Overlay(); 304 dlg.title = 'Metadata for trace'; 305 306 var metadataOverlay = document.createElement( 307 'tr-ui-timeline-view-metadata-overlay'); 308 metadataOverlay.metadata = this.model.metadata; 309 310 dlg.appendChild(metadataOverlay); 311 dlg.visible = true; 312 313 e.stopPropagation(); 314 return false; 315 } 316 showEl.addEventListener('click', onClick.bind(this)); 317 318 this.updateMetadataButtonVisibility_(); 319 }, 320 321 updateMetadataButtonVisibility_: function() { 322 var showEl = this.$.view_metadata_button; 323 showEl.style.display = 324 (this.model && this.model.metadata.length) ? '' : 'none'; 325 }, 326 327 get leftControls() { 328 return this.leftControlsEl_; 329 }, 330 331 get rightControls() { 332 return this.rightControlsEl_; 333 }, 334 335 get collapsingControls() { 336 return this.collapsingControlsEl_; 337 }, 338 339 get viewTitle() { 340 return this.titleEl_.textContent.substring( 341 this.titleEl_.textContent.length - 2); 342 }, 343 344 set viewTitle(text) { 345 if (text === undefined) { 346 this.titleEl_.textContent = ''; 347 this.titleEl_.hidden = true; 348 return; 349 } 350 this.titleEl_.hidden = false; 351 this.titleEl_.textContent = text; 352 }, 353 354 get model() { 355 if (this.trackView_) 356 return this.trackView_.model; 357 return undefined; 358 }, 359 360 set model(model) { 361 var modelInstanceChanged = model != this.model; 362 var modelValid = model && !model.bounds.isEmpty; 363 364 var importWarningsEl = this.shadowRoot.querySelector('#import-warnings'); 365 importWarningsEl.textContent = ''; 366 367 // Remove old trackView if the model has completely changed. 368 if (modelInstanceChanged) { 369 if (this.railScoreSpan_) 370 this.railScoreSpan_.model = undefined; 371 this.trackViewContainer_.textContent = ''; 372 if (this.trackView_) { 373 this.trackView_.viewport.removeEventListener( 374 'change', this.onViewportChanged_); 375 this.trackView_.brushingStateController = undefined; 376 this.trackView_.detach(); 377 this.trackView_ = undefined; 378 } 379 this.brushingStateController_.modelWillChange(); 380 } 381 382 // Create new trackView if needed. 383 if (modelValid && !this.trackView_) { 384 this.trackView_ = document.createElement('tr-ui-timeline-track-view'); 385 this.trackView_.timelineView = this; 386 387 this.trackView.brushingStateController = this.brushingStateController_; 388 389 this.trackViewContainer_.appendChild(this.trackView_); 390 this.trackView_.viewport.addEventListener( 391 'change', this.onViewportChanged_); 392 } 393 394 // Set the model. 395 if (modelValid) { 396 this.trackView_.model = model; 397 this.trackView_.viewport.showFlowEvents = this.showFlowEvents; 398 this.trackView_.viewport.highlightVSync = this.highlightVSync; 399 if (this.railScoreSpan_) 400 this.railScoreSpan_.model = model; 401 402 this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit; 403 } 404 405 if (model) { 406 model.importWarningsThatShouldBeShownToUser.forEach( 407 function(importWarning) { 408 importWarningsEl.addMessage( 409 'Import Warning: ' + importWarning.type + ': ' + 410 importWarning.message); 411 }, this); 412 } 413 414 // Do things that are selection specific 415 if (modelInstanceChanged) { 416 this.updateMetadataButtonVisibility_(); 417 this.brushingStateController_.modelDidChange(); 418 this.onViewportChanged_(); 419 } 420 }, 421 422 get brushingStateController() { 423 return this.brushingStateController_; 424 }, 425 426 get trackView() { 427 return this.trackView_; 428 }, 429 430 get settings() { 431 if (!this.settings_) 432 this.settings_ = new tr.b.Settings(); 433 return this.settings_; 434 }, 435 436 /** 437 * Deprecated. Kept around because third_party code occasionally calls 438 * this to set up embedding. 439 */ 440 set focusElement(value) { 441 throw new Error('This is deprecated. Please set globalMode to true.'); 442 }, 443 444 bindKeyListeners_: function() { 445 var hkc = this.hotkeyController; 446 447 // Shortcuts that *can* steal focus from the console and the filter text 448 // box. 449 hkc.addHotKey(new tr.ui.b.HotKey({ 450 eventType: 'keypress', 451 keyCode: '`'.charCodeAt(0), 452 useCapture: true, 453 thisArg: this, 454 callback: function(e) { 455 this.scriptingCtl_.toggleVisibility(); 456 if (!this.scriptingCtl_.hasFocus) 457 this.focus(); 458 e.stopPropagation(); 459 } 460 })); 461 462 // Shortcuts that *can* steal focus from the filter text box. 463 hkc.addHotKey(new tr.ui.b.HotKey({ 464 eventType: 'keypress', 465 keyCode: '/'.charCodeAt(0), 466 useCapture: true, 467 thisArg: this, 468 callback: function(e) { 469 if (this.scriptingCtl_.hasFocus) 470 return; 471 if (this.findCtl_.hasFocus) 472 this.focus(); 473 else 474 this.findCtl_.focus(); 475 e.preventDefault(); 476 e.stopPropagation(); 477 } 478 })); 479 480 // Shortcuts that *can't* steal focus. 481 hkc.addHotKey(new tr.ui.b.HotKey({ 482 eventType: 'keypress', 483 keyCode: '?'.charCodeAt(0), 484 useCapture: false, 485 thisArg: this, 486 callback: function(e) { 487 this.$.view_help_button.click(); 488 e.stopPropagation(); 489 } 490 })); 491 492 hkc.addHotKey(new tr.ui.b.HotKey({ 493 eventType: 'keypress', 494 keyCode: 'v'.charCodeAt(0), 495 useCapture: false, 496 thisArg: this, 497 callback: function(e) { 498 this.toggleHighlightVSync_(); 499 e.stopPropagation(); 500 } 501 })); 502 }, 503 504 onViewportChanged_: function(e) { 505 var spc = this.sidePanelContainer_; 506 if (!this.trackView_) { 507 spc.rangeOfInterest.reset(); 508 return; 509 } 510 511 var vr = this.trackView_.viewport.interestRange.asRangeObject(); 512 if (!spc.rangeOfInterest.equals(vr)) 513 spc.rangeOfInterest = vr; 514 515 if (this.railScoreSpan_ && this.model) 516 this.railScoreSpan_.model = this.model; 517 }, 518 519 toggleHighlightVSync_: function() { 520 this.highlightVSyncCheckbox_.checked = 521 !this.highlightVSyncCheckbox_.checked; 522 }, 523 524 setFindCtlText: function(string) { 525 this.findCtl_.setText(string); 526 } 527 }); 528 </script> 529</polymer-element> 530