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/ui/tracks/container_track.html"> 9<link rel="import" href="/tracing/base/sorted_array_utils.html"> 10<link rel="import" href="/tracing/model/model_settings.html"> 11<link rel="import" href="/tracing/ui/base/ui.html"> 12 13<script> 14'use strict'; 15 16tr.exportTo('tr.ui.tracks', function() { 17 /** 18 * A track that displays a group of objects in multiple rows. 19 * @constructor 20 * @extends {ContainerTrack} 21 */ 22 var MultiRowTrack = tr.ui.b.define( 23 'multi-row-track', tr.ui.tracks.ContainerTrack); 24 25 MultiRowTrack.prototype = { 26 27 __proto__: tr.ui.tracks.ContainerTrack.prototype, 28 29 decorate: function(viewport) { 30 tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport); 31 this.tooltip_ = ''; 32 this.heading_ = ''; 33 34 this.groupingSource_ = undefined; 35 this.itemsToGroup_ = undefined; 36 37 this.defaultToCollapsedWhenSubRowCountMoreThan = 1; 38 39 this.itemsGroupedOnLastUpdateContents_ = undefined; 40 41 this.currentSubRows_ = []; 42 this.expanded_ = true; 43 }, 44 45 get itemsToGroup() { 46 return this.itemsToGroup_; 47 }, 48 49 setItemsToGroup: function(itemsToGroup, opt_groupingSource) { 50 this.itemsToGroup_ = itemsToGroup; 51 this.groupingSource_ = opt_groupingSource; 52 this.updateContents_(); 53 this.updateExpandedStateFromGroupingSource_(); 54 }, 55 56 get heading() { 57 return this.heading_; 58 }, 59 60 set heading(h) { 61 this.heading_ = h; 62 this.updateContents_(); 63 }, 64 65 get tooltip() { 66 return this.tooltip_; 67 }, 68 69 set tooltip(t) { 70 this.tooltip_ = t; 71 this.updateContents_(); 72 }, 73 74 get subRows() { 75 return this.currentSubRows_; 76 }, 77 78 get hasVisibleContent() { 79 return this.children.length > 0; 80 }, 81 82 get expanded() { 83 return this.expanded_; 84 }, 85 86 set expanded(expanded) { 87 if (this.expanded_ == expanded) 88 return; 89 this.expanded_ = expanded; 90 this.expandedStateChanged_(); 91 }, 92 93 onHeadingClicked_: function(e) { 94 if (this.subRows.length <= 1) 95 return; 96 this.expanded = !this.expanded; 97 98 if (this.groupingSource_) { 99 var modelSettings = new tr.model.ModelSettings( 100 this.groupingSource_.model); 101 modelSettings.setSettingFor(this.groupingSource_, 'expanded', 102 this.expanded); 103 } 104 105 e.stopPropagation(); 106 }, 107 108 updateExpandedStateFromGroupingSource_: function() { 109 if (this.groupingSource_) { 110 var numSubRows = this.subRows.length; 111 var modelSettings = new tr.model.ModelSettings( 112 this.groupingSource_.model); 113 if (numSubRows > 1) { 114 var defaultExpanded; 115 if (numSubRows > this.defaultToCollapsedWhenSubRowCountMoreThan) { 116 defaultExpanded = false; 117 } else { 118 defaultExpanded = true; 119 } 120 this.expanded = modelSettings.getSettingFor( 121 this.groupingSource_, 'expanded', defaultExpanded); 122 } else { 123 this.expanded = undefined; 124 } 125 } 126 }, 127 128 expandedStateChanged_: function() { 129 var minH = Math.max(2, Math.ceil(18 / this.children.length)); 130 var h = (this.expanded_ ? 18 : minH) + 'px'; 131 132 for (var i = 0; i < this.children.length; i++) { 133 this.children[i].height = h; 134 if (i === 0) 135 this.children[i].arrowVisible = true; 136 this.children[i].expanded = this.expanded; 137 } 138 139 if (this.children.length === 1) { 140 this.children[0].expanded = true; 141 this.children[0].arrowVisible = false; 142 } 143 }, 144 145 updateContents_: function() { 146 tr.ui.tracks.ContainerTrack.prototype.updateContents_.call(this); 147 if (!this.itemsToGroup_) { 148 this.updateHeadingAndTooltip_(); 149 this.currentSubRows_ = []; 150 return; 151 } 152 153 if (this.areArrayContentsSame_(this.itemsGroupedOnLastUpdateContents_, 154 this.itemsToGroup_)) { 155 this.updateHeadingAndTooltip_(); 156 return; 157 } 158 159 this.itemsGroupedOnLastUpdateContents_ = this.itemsToGroup_; 160 161 this.detach(); 162 if (!this.itemsToGroup_.length) { 163 this.currentSubRows_ = []; 164 return; 165 } 166 var subRows = this.buildSubRows_(this.itemsToGroup_); 167 this.currentSubRows_ = subRows; 168 for (var srI = 0; srI < subRows.length; srI++) { 169 var subRow = subRows[srI]; 170 if (!subRow.length) 171 continue; 172 var track = this.addSubTrack_(subRow); 173 track.addEventListener( 174 'heading-clicked', this.onHeadingClicked_.bind(this)); 175 } 176 this.updateHeadingAndTooltip_(); 177 this.expandedStateChanged_(); 178 }, 179 180 updateHeadingAndTooltip_: function() { 181 if (!this.firstChild) 182 return; 183 this.firstChild.heading = this.heading_; 184 this.firstChild.tooltip = this.tooltip_; 185 }, 186 187 /** 188 * Breaks up the list of slices into N rows, each of which is a list of 189 * slices that are non overlapping. 190 */ 191 buildSubRows_: function(itemsToGroup) { 192 throw new Error('Not implemented'); 193 }, 194 195 addSubTrack_: function(subRowItems) { 196 throw new Error('Not implemented'); 197 }, 198 199 areArrayContentsSame_: function(a, b) { 200 if (!a || !b) 201 return false; 202 if (!a.length || !b.length) 203 return false; 204 if (a.length != b.length) 205 return false; 206 for (var i = 0; i < a.length; ++i) { 207 if (a[i] != b[i]) 208 return false; 209 } 210 return true; 211 } 212 }; 213 214 return { 215 MultiRowTrack: MultiRowTrack 216 }; 217}); 218</script> 219