Chromium Code Reviews| Index: runtime/observatory/lib/src/elements/stack_trace_tree_config.dart |
| diff --git a/runtime/observatory/lib/src/elements/stack_trace_tree_config.dart b/runtime/observatory/lib/src/elements/stack_trace_tree_config.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8a04d89e440c2ae1a03f2bc11f6ddf2f0acd24df |
| --- /dev/null |
| +++ b/runtime/observatory/lib/src/elements/stack_trace_tree_config.dart |
| @@ -0,0 +1,301 @@ |
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +import 'dart:async'; |
| +import 'dart:html'; |
| +import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| +import 'package:observatory/src/elements/helpers/tag.dart'; |
| + |
| +enum ProfileTreeDirection { |
| + Inclusive, |
|
Cutch
2016/08/02 15:52:20
enum values are lowerCamelCase
cbernaschina
2016/08/02 17:40:24
Done.
|
| + Exclusive |
| +} |
| + |
| +enum ProfileTreeMode { |
| + Code, |
| + Function, |
| +} |
| + |
| +class StackTraceTreeConfigChangedEvent { |
| + final StackTraceTreeConfigElement element; |
| + StackTraceTreeConfigChangedEvent(this.element); |
| +} |
| + |
| +class StackTraceTreeConfigElement extends HtmlElement implements Renderable { |
| + static const tag = |
| + const Tag<StackTraceTreeConfigElement>('stack-trace-tree-config'); |
| + |
| + RenderingScheduler<StackTraceTreeConfigElement> _r; |
| + |
| + Stream<RenderedEvent<StackTraceTreeConfigElement>> get onRendered => |
| + _r.onRendered; |
| + |
| + StreamController<StackTraceTreeConfigChangedEvent> _onModeChange = |
| + new StreamController<StackTraceTreeConfigChangedEvent>.broadcast(); |
| + StreamController<StackTraceTreeConfigChangedEvent> _onDirectionChange = |
| + new StreamController<StackTraceTreeConfigChangedEvent>.broadcast(); |
| + StreamController<StackTraceTreeConfigChangedEvent> _onFilterChange = |
| + new StreamController<StackTraceTreeConfigChangedEvent>.broadcast(); |
| + Stream<StackTraceTreeConfigChangedEvent> get onModeChange => |
| + _onModeChange.stream; |
| + Stream<StackTraceTreeConfigChangedEvent> get onDirectionChange => |
| + _onDirectionChange.stream; |
| + Stream<StackTraceTreeConfigChangedEvent> get onFilterChange => |
| + _onFilterChange.stream; |
| + |
| + bool _showMode; |
| + bool _showDirection; |
| + bool _showFilter; |
| + ProfileTreeMode _mode; |
| + ProfileTreeDirection _direction; |
| + String _filter; |
| + |
| + bool get showMode => _showMode; |
| + bool get showDirection => _showDirection; |
| + bool get showFilter => _showFilter; |
| + ProfileTreeMode get mode => _mode; |
| + ProfileTreeDirection get direction => _direction; |
| + String get filter => _filter; |
| + |
| + set showMode(bool value) => _showMode = _r.checkAndReact(_showMode, value); |
| + set showDirection(bool value) => |
| + _showDirection = _r.checkAndReact(_showDirection, value); |
| + set showFilter(bool value) => |
| + _showFilter = _r.checkAndReact(_showFilter, value); |
| + set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value); |
| + set direction(ProfileTreeDirection value) => |
| + _direction = _r.checkAndReact(_direction, value); |
| + set filter(String value) => _filter = _r.checkAndReact(_filter, value); |
| + |
| + factory StackTraceTreeConfigElement({bool showMode: true, |
| + bool showDirection: true, bool showFilter: true, String filter: '', |
| + ProfileTreeMode mode: ProfileTreeMode.Function, |
| + ProfileTreeDirection direction: ProfileTreeDirection.Exclusive, |
| + RenderingQueue queue}) { |
| + assert(showMode != null); |
| + assert(showDirection != null); |
| + assert(showFilter != null); |
| + assert(mode != null); |
| + assert(direction != null); |
| + assert(filter != null); |
| + StackTraceTreeConfigElement e = document.createElement(tag.name); |
| + e._r = new RenderingScheduler(e, queue: queue); |
| + e._showMode = showMode; |
| + e._showDirection = showDirection; |
| + e._showFilter = showFilter; |
| + e._mode = mode; |
| + e._direction = direction; |
| + e._filter = filter; |
| + return e; |
| + } |
| + |
| + StackTraceTreeConfigElement.created() : super.created(); |
| + |
| + @override |
| + void attached() { |
| + super.attached(); |
| + _r.enable(); |
| + } |
| + |
| + @override |
| + void detached() { |
| + super.detached(); _r.disable(notify: true); |
| + children = const []; |
| + } |
| + |
| + void render() { |
| + children = [ |
| + new DivElement()..classes = ['content-centered-big'] |
| + ..children = [ |
| + new HeadingElement.h2()..text = 'Tree display', |
| + new HRElement(), |
| + new DivElement()..classes = ['row'] |
| + ..children = [ |
| + new DivElement()..classes = ['memberList'] |
| + ..children = _createMembers() |
| + ] |
| + ] |
| + ]; |
| + } |
| + |
| + List<Element> _createMembers() { |
| + var members = <Element>[]; |
| + if (_showMode) { |
| + members.add( |
| + new DivElement()..classes = ['memberItem'] |
| + ..children = [ |
| + new DivElement()..classes = ['memberName']..text = 'Mode', |
| + new DivElement()..classes = ['memberValue'] |
| + ..children = _createModeSelect() |
| + ] |
| + ); |
| + } |
| + if (_showDirection) { |
| + members.add( |
| + new DivElement()..classes = ['memberItem'] |
| + ..children = [ |
| + new DivElement()..classes = ['memberName'] |
| + ..text = 'Call Tree Direction', |
| + new SpanElement()..classes = ['memberValue'] |
| + ..children = _createDirectionSelect() |
| + ] |
| + ); |
| + } |
| + if (showFilter) { |
| + members.add( |
| + new DivElement()..classes = ['memberItem'] |
| + ..children = [ |
| + new DivElement()..classes = ['memberName'] |
| + ..text = 'Call Tree Filter' |
| + ..title = 'case-sensitive substring match', |
| + new SpanElement()..classes = ['memberValue'] |
| + ..children = _createFilter() |
| + ] |
| + ); |
| + } |
| + return members; |
| + } |
| + |
| + List<Element> _createModeSelect() { |
| + var s; |
| + return [ |
| + s = new SelectElement()..value = modeToString(_mode) |
| + ..children = ProfileTreeMode.values.map((mode) { |
| + return new OptionElement(value : modeToString(mode), |
| + selected: _mode == mode) |
| + ..text = modeToString(mode); |
| + }).toList(growable: false) |
| + ..onChange.listen((_) { |
| + _mode = ProfileTreeMode.values[s.selectedIndex]; |
| + }) |
| + ..onChange.map(_toEvent).listen(_triggerModeChange), |
| + ]; |
| + } |
| + |
| + List<Element> _createDirectionSelect() { |
| + var s; |
| + return [ |
| + s = new SelectElement()..value = directionToString(_direction) |
| + ..children = ProfileTreeDirection.values.map((direction) { |
| + return new OptionElement(value: directionToString(direction), |
| + selected: _direction == direction) |
| + ..text = directionToString(direction); |
| + }).toList(growable: false) |
| + ..onChange.listen((_) { |
| + _direction = ProfileTreeDirection.values[s.selectedIndex]; |
| + }) |
| + ..onChange.map(_toEvent).listen(_triggerDirectionChange), |
| + new SpanElement()..text = 'Tree is rooted at ' + |
| + (_direction == 'Down' ? '"main"' : 'function / code') + |
| + '. Child nodes are callers.' |
| + ]; |
| + } |
| + |
| + List<Element> _createFilter(){ |
| + var t; |
| + return [ |
| + t = new TextInputElement()..placeholder = 'Search filter' |
| + ..value = filter |
| + ..onChange.listen((_) { _filter = t.value; }) |
| + ..onChange.map(_toEvent).listen(_triggerFilterChange) |
| + ]; |
| + } |
| + |
| + static String modeToString(ProfileTreeMode mode) { |
| + switch (mode) { |
| + case ProfileTreeMode.Code: return 'Code'; |
| + case ProfileTreeMode.Function: return 'Function'; |
| + } |
| + throw new Exception('Unknown ProfileTreeMode'); |
| + } |
| + |
| + static String directionToString(ProfileTreeDirection direction) { |
| + switch (direction) { |
| + case ProfileTreeDirection.Inclusive: return 'Top down'; |
| + case ProfileTreeDirection.Exclusive: return 'Bottom up'; |
| + } |
| + throw new Exception('Unknown ProfileTreeDirection'); |
| + } |
| + |
| + StackTraceTreeConfigChangedEvent _toEvent(_) { |
| + return new StackTraceTreeConfigChangedEvent(this); |
| + } |
| + |
| + void _triggerModeChange(e) => _onModeChange.add(e); |
| + void _triggerDirectionChange(e) => _onDirectionChange.add(e); |
| + void _triggerFilterChange(e) => _onFilterChange.add(e); |
| + |
| + |
| +} |
| + |
| +/*<link rel="import" href="../../../../packages/polymer/polymer.html"> |
| + |
| +<polymer-element name="stack-trace-tree-config"> |
| + <template> |
| + <link rel="stylesheet" href="css/shared.css"> |
| + <style> |
| + .statusBox { |
| + height: 100%; |
| + padding: 0.5em; |
| + } |
| + .row { |
| + display: flex; |
| + } |
| + </style> |
| + <div class="content-centered-big"> |
| + <template if="{{ show }}"> |
| + <h2>Tree display</h2> |
| + <hr> |
| + <div class="row"> |
| + <div> |
| + <div class="memberList"> |
| + <template if="{{ showModeSelector }}"> |
| + <div class="memberItem"> |
| + <div class="memberName">Mode</div> |
| + <div class="memberValue"> |
| + <select value="{{modeSelector}}"> |
| + <option value="Code">Code</option> |
| + <option value="Function">Function</option> |
| + </select> |
| + </div> |
| + </div> |
| + </template> |
| + <template if="{{ showDirectionSelector }}"> |
| + <div class="memberItem"> |
| + <div class="memberName">Call Tree Direction</div> |
| + <span class="memberValue"> |
| + <select value="{{directionSelector}}"> |
| + <option value="Down">Top down</option> |
| + <option value="Up">Bottom up</option> |
| + </select> |
| + <template if="{{ directionSelector == 'Down' }}"> |
| + <span> |
| + Tree is rooted at "main". Child nodes are callees. |
| + </span> |
| + </template> |
| + <template if="{{ directionSelector == 'Up' }}"> |
| + <span> |
| + Tree is rooted at executing function / code. Child nodes are callers. |
| + </span> |
| + </template> |
| + </span> |
| + </div> |
| + </template> |
| + <template if="{{ showFilter }}"> |
| + <div class="memberItem"> |
| + <div title="case-sensitive substring match" class="memberName">Call Tree Filter</div> |
| + <span class="memberValue"> |
| + <input type="text" placeholder="Search filter" id="filterInput"> |
| + </span> |
| + </div> |
| + </template> |
| + </div> |
| + </div> |
| + </div> |
| + </template> |
| + </div> |
| + </template> |
| +</polymer-element> |
| + |
| +<script type="application/dart" src="stack_trace_tree_config.dart"></script>*/ |