Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(609)

Side by Side Diff: runtime/observatory/lib/src/app/view_model.dart

Issue 965593002: Improved profiler view and inclusive profile tree (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of app; 5 part of app;
6 6
7 abstract class TableTreeRow extends Observable { 7 abstract class TableTreeRow extends Observable {
8 static const arrowRight = '\u2192'; 8 static const arrowRight = '\u2192';
9 static const arrowDownRight = '\u21b3'; 9 static const arrowDownRight = '\u21b3';
10 // Number of pixels each subtree is indented. 10 // Number of ems each subtree is indented.
11 static const subtreeIndent = 16; 11 static const subtreeIndent = 2;
12
13 TableTreeRow(this.tree, TableTreeRow parent) :
14 parent = parent,
15 depth = parent != null ? parent.depth + 1 : 0 {
16 }
12 17
13 final TableTree tree; 18 final TableTree tree;
14 final TableTreeRow parent; 19 final TableTreeRow parent;
15 final int depth; 20 final int depth;
16 final List<TableTreeRow> children = new List<TableTreeRow>(); 21 final List<TableTreeRow> children = new List<TableTreeRow>();
17 final List<TableCellElement> tableColumns = new List<TableCellElement>(); 22 final List<TableCellElement> _tableColumns = new List<TableCellElement>();
23 final List<DivElement> flexColumns = new List<DivElement>();
18 SpanElement _expander; 24 SpanElement _expander;
19 TableRowElement _tr; 25 TableRowElement _tr;
20 TableRowElement get tr { 26 TableRowElement get tr => _tr;
21 assert(_tr != null);
22 return _tr;
23 }
24
25 TableTreeRow(this.tree, TableTreeRow parent) :
26 parent = parent,
27 depth = parent != null ? parent.depth+1 : 0 {
28 }
29
30 bool _expanded = false; 27 bool _expanded = false;
31 bool get expanded => _expanded; 28 bool get expanded => _expanded;
32 set expanded(bool expanded) { 29 set expanded(bool expanded) {
33 var changed = _expanded != expanded; 30 var changed = _expanded != expanded;
34 _expanded = expanded; 31 _expanded = expanded;
35 if (changed) { 32 if (changed) {
36 // If the state has changed, fire callbacks. 33 // If the state has changed, fire callbacks.
37 if (_expanded) { 34 if (_expanded) {
38 _onExpand(); 35 _onExpand();
39 } else { 36 } else {
40 _onCollapse(); 37 _onCollapse();
41 } 38 }
42 } 39 }
43 } 40 }
44 41
45 bool expandOrCollapse() { 42 /// Fired when the tree row is being expanded.
43 void _onExpand() {
44 _updateExpanderView();
45 }
46
47 /// Fired when the tree row is being collapsed.
48 void _onCollapse() {
49 for (var child in children) {
50 child.onHide();
51 }
52 _updateExpanderView();
53 }
54
55 bool toggle() {
46 expanded = !expanded; 56 expanded = !expanded;
47 return expanded; 57 return expanded;
48 } 58 }
49 59
50 bool hasChildren(); 60 HtmlElement _makeColorBlock(String backgroundColor) {
61 var colorBlock = new DivElement();
62 colorBlock.style.minWidth = '2px';
63 colorBlock.style.backgroundColor = backgroundColor;
64 return colorBlock;
65 }
51 66
52 String _backgroundColorClassForRow() { 67 HtmlElement _makeExpander() {
53 const colors = const ['rowColor0', 'rowColor1', 'rowColor2', 'rowColor3', 68 var expander = new SpanElement();
54 'rowColor4', 'rowColor5', 'rowColor6', 'rowColor7', 69 expander.style.minWidth = '1.5em';
55 'rowColor8']; 70 expander.onClick.listen(onClick);
56 var index = (depth - 1) % colors.length; 71 return expander;
57 return colors[index]; 72 }
73
74 void onClick(Event e) {
75 e.stopPropagation();
76 tree.toggle(this);
58 } 77 }
59 78
60 void _buildRow() { 79 void _buildRow() {
80 const List backgroundColors = const [
81 '#F44336',
82 '#3F51B5',
83 '#673AB7',
84 '#4CAF50',
85 '#FF9800',
siva 2015/03/02 21:58:44 More readable const variables for these values?
Cutch 2015/03/02 22:48:19 Done.
86 ];
61 _tr = new TableRowElement(); 87 _tr = new TableRowElement();
62 for (var i = 0; i < tree.columnCount; i++) { 88 for (var i = 0; i < tree.columnCount; i++) {
63 var cell = _tr.insertCell(-1); 89 var cell = _tr.insertCell(-1);
64 cell.classes.add(_backgroundColorClassForRow()); 90 _tableColumns.add(cell);
65 tableColumns.add(cell); 91 var flex = new DivElement();
92 flex.classes.add('flex-row');
93 cell.children.add(flex);
94 flexColumns.add(flex);
66 } 95 }
67 var firstColumn = tableColumns[0]; 96 var firstColumn = flexColumns[0];
68 var columnContainer = new DivElement(); 97 _tableColumns[0].style.paddingLeft = '${(depth - 1) * subtreeIndent}em';
69 columnContainer.classes.add('flex-row'); 98 var backgroundColor = '#FAFAFA';
siva 2015/03/02 21:58:44 Ditto comment.
Cutch 2015/03/02 22:48:19 Done.
70 _expander = new SpanElement(); 99 if (depth > 1) {
71 _expander.style.display = 'inline-block'; 100 var colorIndex = (depth - 1) % backgroundColors.length;
72 _expander.style.display = 'inline-block'; 101 backgroundColor = backgroundColors[colorIndex];
73 _expander.style.minWidth = '1.5em'; 102 }
74 _expander.onClick.listen(onClick); 103 var colorBlock = _makeColorBlock(backgroundColor);
75 columnContainer.children.add(_expander); 104 firstColumn.children.add(colorBlock);
76 firstColumn.style.paddingLeft = '${depth * subtreeIndent}px'; 105 _expander = _makeExpander();
77 firstColumn.children.add(columnContainer); 106 firstColumn.children.add(_expander);
78 updateExpanderView(); 107 // Enable expansion by clicking anywhere on the first column.
108 firstColumn.onClick.listen(onClick);
109 _updateExpanderView();
79 } 110 }
80 111
81 void updateExpanderView() { 112 void _updateExpanderView() {
82 if (_expander == null) { 113 if (_expander == null) {
83 return; 114 return;
84 } 115 }
85 if (!hasChildren()) { 116 if (!hasChildren()) {
86 _expander.style.visibility = 'hidden'; 117 _expander.style.visibility = 'hidden';
87 _expander.style.cursor = 'auto'; 118 _expander.classes.remove('pointer');
88 return; 119 return;
89 } else { 120 } else {
90 _expander.style.visibility = 'visible'; 121 _expander.style.visibility = 'visible';
91 _expander.style.cursor = 'pointer'; 122 _expander.classes.add('pointer');
92 } 123 }
93 _expander.text = expanded ? arrowDownRight : arrowRight; 124 _expander.children.clear();
125 _expander.children.add(expanded ?
126 new Element.tag('icon-expand-more') :
127 new Element.tag('icon-chevron-right'));
94 } 128 }
95 129
130 bool hasChildren();
131
96 /// Fired when the tree row is being shown. 132 /// Fired when the tree row is being shown.
97 /// Populate tr and add logical children here. 133 /// Populate tr and add logical children here.
98 void onShow() { 134 void onShow() {
99 assert(_tr == null); 135 assert(_tr == null);
100 _buildRow(); 136 _buildRow();
101 } 137 }
102 138
103 /// Fired when the tree row is being hidden. 139 /// Fired when the tree row is being hidden.
104 void onHide() { 140 void onHide() {
105 assert(_tr != null);
106 _tr = null; 141 _tr = null;
107 tableColumns.clear();
108 _expander = null; 142 _expander = null;
109 } 143 if (_tableColumns != null) {
110 144 _tableColumns.clear();
111 /// Fired when the tree row is being expanded.
112 void _onExpand() {
113 for (var child in children) {
114 child.onShow();
115 child.updateExpanderView();
116 } 145 }
117 updateExpanderView(); 146 if (flexColumns != null) {
118 } 147 flexColumns.clear();
119
120 /// Fired when the tree row is being collapsed.
121 void _onCollapse() {
122 for (var child in children) {
123 child.onHide();
124 } 148 }
125 updateExpanderView();
126 }
127
128 void onClick(Event e) {
129 tree.toggle(this);
130 e.stopPropagation();
131 } 149 }
132 } 150 }
133 151
134 class TableTree extends Observable { 152 class TableTree extends Observable {
135 final TableSectionElement tableBody; 153 final TableSectionElement tableBody;
136 final List<TableTreeRow> rows = []; 154 final List<TableTreeRow> rows = [];
137 final int columnCount; 155 final int columnCount;
138 156 var _operation;
rmacnak 2015/03/02 22:25:26 Consider Future _pendingOperation;
Cutch 2015/03/02 22:48:19 Done.
139 /// Create a table tree with column [headers]. 157 /// Create a table tree with column [headers].
140 TableTree(this.tableBody, this.columnCount); 158 TableTree(this.tableBody, this.columnCount);
141 159
142 void clear() { 160 void clear() {
143 tableBody.children.clear(); 161 tableBody.children.clear();
144 rows.clear(); 162 rows.clear();
145 } 163 }
146 164
147 /// Initialize the table tree with the list of root children. 165 /// Initialize the table tree with the list of root children.
148 void initialize(TableTreeRow root) { 166 void initialize(TableTreeRow root) {
149 clear(); 167 clear();
150 root.onShow(); 168 root.onShow();
151 rows.addAll(root.children); 169 toggle(root);
152 for (var i = 0; i < rows.length; i++) {
153 rows[i].onShow();
154 tableBody.children.add(rows[i].tr);
155 }
156 } 170 }
157 171
158 /// Toggle expansion of row in tree. 172 /// Toggle expansion of row in tree.
159 void toggle(TableTreeRow row) { 173 toggle(TableTreeRow row) async {
160 if (row.expandOrCollapse()) { 174 if (_operation != null) {
161 _expand(row); 175 return;
176 }
177 if (row.toggle()) {
178 document.body.classes.add('busy');
179 _operation = _expand(row);
180 await _operation;
181 _operation = null;
182 document.body.classes.remove('busy');
183 if (row.children.length == 1) {
184 // Auto expand single child.
185 await toggle(row.children[0]);
186 }
162 } else { 187 } else {
163 _collapse(row); 188 document.body.classes.add('busy');
189 _operation = _collapse(row);
190 await _operation;
191 _operation = null;
192 document.body.classes.remove('busy');
164 } 193 }
165 } 194 }
166 195
167 int _index(TableTreeRow row) => rows.indexOf(row); 196 int _index(TableTreeRow row) => rows.indexOf(row);
168 197
169 void _expand(TableTreeRow row) { 198 _insertRow(index, child) {
199 rows.insert(index, child);
200 tableBody.children.insert(index, child.tr);
201 }
202
203 _expand(TableTreeRow row) async {
170 int index = _index(row); 204 int index = _index(row);
171 assert(index != -1); 205 if ((index == -1) && (rows.length != 0)) {
172 rows.insertAll(index + 1, row.children); 206 return;
173 for (var i = 0; i < row.children.length; i++) { 207 }
174 tableBody.children.insert(index + i + 1, row.children[i].tr); 208 assert((index != -1) || (rows.length == 0));
209 var i = 0;
210 var addPerIteration = 2;
211 while (i < row.children.length) {
212 await window.animationFrame;
213 for (var j = 0; j < addPerIteration; j++) {
214 if (i == row.children.length) {
215 break;
216 }
217 var child = row.children[i];
218 child.onShow();
219 child._updateExpanderView();
220 _insertRow(index + i + 1, row.children[i]);
rmacnak 2015/03/02 22:25:26 row.children[i] -> child
Cutch 2015/03/02 22:48:19 Done.
221 i++;
222 }
175 } 223 }
176 } 224 }
177 225
178 void _collapse(TableTreeRow row) { 226 _collapseSync(TableTreeRow row) {
179 var childCount = row.children.length; 227 var childCount = row.children.length;
180 if (childCount == 0) { 228 if (childCount == 0) {
181 return; 229 return;
182 } 230 }
183 for (var i = 0; i < childCount; i++) { 231 for (var i = 0; i < childCount; i++) {
184 // Close all inner rows. 232 // Close all inner rows.
185 if (row.children[i].expanded) { 233 if (row.children[i].expanded) {
186 _collapse(row.children[i]); 234 _collapseSync(row.children[i]);
187 } 235 }
188 } 236 }
189 // Collapse this row. 237 // Collapse this row.
190 row.expanded = false; 238 row.expanded = false;
191 // Remove all children. 239 // Remove all children.
192 int index = _index(row); 240 int index = _index(row);
193 rows.removeRange(index + 1, index + 1 + childCount);
194 for (var i = 0; i < childCount; i++) { 241 for (var i = 0; i < childCount; i++) {
242 rows.removeAt(index + 1);
195 tableBody.children.removeAt(index + 1); 243 tableBody.children.removeAt(index + 1);
196 } 244 }
197 } 245 }
246
247 _collapse(TableTreeRow row) async {
248 _collapseSync(row);
249 }
198 } 250 }
199 251
200 typedef String ValueFormatter(dynamic value); 252 typedef String ValueFormatter(dynamic value);
201 253
202 class SortedTableColumn { 254 class SortedTableColumn {
203 static String toStringFormatter(dynamic v) { 255 static String toStringFormatter(dynamic v) {
204 return v != null ? v.toString() : '<null>'; 256 return v != null ? v.toString() : '<null>';
205 } 257 }
206 final String label; 258 final String label;
207 final ValueFormatter formatter; 259 final ValueFormatter formatter;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 if (column != _sortColumnIndex) { 342 if (column != _sortColumnIndex) {
291 return columns[column].label + '\u2003'; 343 return columns[column].label + '\u2003';
292 } 344 }
293 return columns[column].label + (_sortDescending ? arrowUp : arrowDown); 345 return columns[column].label + (_sortDescending ? arrowUp : arrowDown);
294 } 346 }
295 347
296 dynamic getValue(int row, int column) { 348 dynamic getValue(int row, int column) {
297 return rows[row].values[column]; 349 return rows[row].values[column];
298 } 350 }
299 } 351 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698