| OLD | NEW |
| 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 library class_tree_element; | 5 library class_tree_element; |
| 6 | 6 |
| 7 import 'dart:html'; | 7 import 'dart:html'; |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 import 'package:observatory/models.dart' as M; | 9 import 'package:observatory/models.dart' as M; |
| 10 import 'package:observatory/src/elements/class_ref.dart'; | 10 import 'package:observatory/src/elements/class_ref.dart'; |
| 11 import 'package:observatory/src/elements/containers/virtual_tree.dart'; | 11 import 'package:observatory/src/elements/containers/virtual_tree.dart'; |
| 12 import 'package:observatory/src/elements/helpers/nav_bar.dart'; | 12 import 'package:observatory/src/elements/helpers/nav_bar.dart'; |
| 13 import 'package:observatory/src/elements/helpers/nav_menu.dart'; | 13 import 'package:observatory/src/elements/helpers/nav_menu.dart'; |
| 14 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; | 14 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 15 import 'package:observatory/src/elements/helpers/tag.dart'; | 15 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 16 import 'package:observatory/src/elements/nav/isolate_menu.dart'; | 16 import 'package:observatory/src/elements/nav/isolate_menu.dart'; |
| 17 import 'package:observatory/src/elements/nav/notify.dart'; | 17 import 'package:observatory/src/elements/nav/notify.dart'; |
| 18 import 'package:observatory/src/elements/nav/top_menu.dart'; | 18 import 'package:observatory/src/elements/nav/top_menu.dart'; |
| 19 import 'package:observatory/src/elements/nav/vm_menu.dart'; | 19 import 'package:observatory/src/elements/nav/vm_menu.dart'; |
| 20 | 20 |
| 21 | 21 class ClassTreeElement extends HtmlElement implements Renderable { |
| 22 class ClassTreeElement extends HtmlElement implements Renderable{ | 22 static const tag = |
| 23 static const tag = const Tag<ClassTreeElement>('class-tree', | 23 const Tag<ClassTreeElement>('class-tree', dependencies: const [ |
| 24 dependencies: const [ClassRefElement.tag, | 24 ClassRefElement.tag, |
| 25 NavIsolateMenuElement.tag, | 25 NavIsolateMenuElement.tag, |
| 26 NavNotifyElement.tag, | 26 NavNotifyElement.tag, |
| 27 NavTopMenuElement.tag, | 27 NavTopMenuElement.tag, |
| 28 NavVMMenuElement.tag, | 28 NavVMMenuElement.tag, |
| 29 VirtualTreeElement.tag]); | 29 VirtualTreeElement.tag |
| 30 ]); |
| 30 | 31 |
| 31 RenderingScheduler _r; | 32 RenderingScheduler _r; |
| 32 | 33 |
| 33 Stream<RenderedEvent<ClassTreeElement>> get onRendered => _r.onRendered; | 34 Stream<RenderedEvent<ClassTreeElement>> get onRendered => _r.onRendered; |
| 34 | 35 |
| 35 M.VMRef _vm; | 36 M.VMRef _vm; |
| 36 M.IsolateRef _isolate; | 37 M.IsolateRef _isolate; |
| 37 M.EventRepository _events; | 38 M.EventRepository _events; |
| 38 M.NotificationRepository _notifications; | 39 M.NotificationRepository _notifications; |
| 39 M.ClassRepository _classes; | 40 M.ClassRepository _classes; |
| 40 M.Class _object; | 41 M.Class _object; |
| 41 final _subclasses = <String, Iterable<M.Class>>{}; | 42 final _subclasses = <String, Iterable<M.Class>>{}; |
| 42 final _mixins = <String, List<M.Instance>>{}; | 43 final _mixins = <String, List<M.Instance>>{}; |
| 43 | 44 |
| 44 factory ClassTreeElement(M.VMRef vm, M.IsolateRef isolate, | 45 factory ClassTreeElement( |
| 45 M.EventRepository events, | 46 M.VMRef vm, |
| 46 M.NotificationRepository notifications, | 47 M.IsolateRef isolate, |
| 47 M.ClassRepository classes, | 48 M.EventRepository events, |
| 48 {RenderingQueue queue}) { | 49 M.NotificationRepository notifications, |
| 50 M.ClassRepository classes, |
| 51 {RenderingQueue queue}) { |
| 49 assert(vm != null); | 52 assert(vm != null); |
| 50 assert(isolate != null); | 53 assert(isolate != null); |
| 51 assert(events != null); | 54 assert(events != null); |
| 52 assert(notifications != null); | 55 assert(notifications != null); |
| 53 assert(classes != null); | 56 assert(classes != null); |
| 54 ClassTreeElement e = document.createElement(tag.name); | 57 ClassTreeElement e = document.createElement(tag.name); |
| 55 e._r = new RenderingScheduler(e, queue: queue); | 58 e._r = new RenderingScheduler(e, queue: queue); |
| 56 e._vm = vm; | 59 e._vm = vm; |
| 57 e._isolate = isolate; | 60 e._isolate = isolate; |
| 58 e._events = events; | 61 e._events = events; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 85 new NavTopMenuElement(queue: _r.queue), | 88 new NavTopMenuElement(queue: _r.queue), |
| 86 new NavVMMenuElement(_vm, _events, queue: _r.queue), | 89 new NavVMMenuElement(_vm, _events, queue: _r.queue), |
| 87 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), | 90 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), |
| 88 navMenu('class hierarchy'), | 91 navMenu('class hierarchy'), |
| 89 new NavNotifyElement(_notifications, queue: _r.queue) | 92 new NavNotifyElement(_notifications, queue: _r.queue) |
| 90 ]), | 93 ]), |
| 91 new DivElement() | 94 new DivElement() |
| 92 ..classes = ['content-centered'] | 95 ..classes = ['content-centered'] |
| 93 ..children = [ | 96 ..children = [ |
| 94 new HeadingElement.h1()..text = 'Class Hierarchy', | 97 new HeadingElement.h1()..text = 'Class Hierarchy', |
| 95 new BRElement(), new HRElement(), | 98 new BRElement(), |
| 96 _object == null ? (new HeadingElement.h2()..text = 'Loading...') | 99 new HRElement(), |
| 97 : _createTree() | 100 _object == null |
| 101 ? (new HeadingElement.h2()..text = 'Loading...') |
| 102 : _createTree() |
| 98 ] | 103 ] |
| 99 ]; | 104 ]; |
| 100 } | 105 } |
| 101 | 106 |
| 102 Element _createTree() { | 107 Element _createTree() { |
| 103 _tree = new VirtualTreeElement(_create, _update, _children, | 108 _tree = new VirtualTreeElement(_create, _update, _children, |
| 104 items: [_object], queue: _r.queue); | 109 items: [_object], queue: _r.queue); |
| 105 _tree.expand(_object, autoExpandSingleChildNodes: true); | 110 _tree.expand(_object, autoExpandSingleChildNodes: true); |
| 106 return _tree; | 111 return _tree; |
| 107 } | 112 } |
| 108 | 113 |
| 109 Future _refresh() async { | 114 Future _refresh() async { |
| 110 _object = null; | 115 _object = null; |
| 111 _subclasses.clear(); | 116 _subclasses.clear(); |
| 112 _mixins.clear(); | 117 _mixins.clear(); |
| 113 _object = await _register(await _classes.getObject(_isolate)); | 118 _object = await _register(await _classes.getObject(_isolate)); |
| 114 _r.dirty(); | 119 _r.dirty(); |
| 115 } | 120 } |
| 116 | 121 |
| 117 Future<M.Class> _register(M.Class cls) async { | 122 Future<M.Class> _register(M.Class cls) async { |
| 118 _subclasses[cls.id] = await Future.wait( | 123 _subclasses[cls.id] = await Future.wait( |
| 119 (await Future.wait(cls.subclasses.map(_getActualChildrens))) | 124 (await Future.wait(cls.subclasses.map(_getActualChildrens))) |
| 120 .expand((f) => f) | 125 .expand((f) => f) |
| 121 .map(_register) | 126 .map(_register)); |
| 122 ); | |
| 123 return cls; | 127 return cls; |
| 124 } | 128 } |
| 125 | 129 |
| 126 Future<Iterable<M.Class>> _getActualChildrens(M.ClassRef ref) async { | 130 Future<Iterable<M.Class>> _getActualChildrens(M.ClassRef ref) async { |
| 127 var cls = await _classes.get(_isolate, ref.id); | 131 var cls = await _classes.get(_isolate, ref.id); |
| 128 if (cls.isPatch) { | 132 if (cls.isPatch) { |
| 129 return const []; | 133 return const []; |
| 130 } | 134 } |
| 131 if (cls.mixin == null) { | 135 if (cls.mixin == null) { |
| 132 return [cls]; | 136 return [cls]; |
| 133 } | 137 } |
| 134 return (await Future.wait(cls.subclasses.map(_getActualChildrens))) | 138 return (await Future.wait(cls.subclasses.map(_getActualChildrens))) |
| 135 .expand((f) => f) | 139 .expand((f) => f) |
| 136 ..forEach((subcls) { | 140 ..forEach((subcls) { |
| 137 _mixins[subcls.id] = (_mixins[subcls.id] ?? [])..add(cls.mixin); | 141 _mixins[subcls.id] = (_mixins[subcls.id] ?? [])..add(cls.mixin); |
| 138 }); | 142 }); |
| 139 } | 143 } |
| 140 | 144 |
| 141 static Element _create(toggle) { | 145 static Element _create(toggle) { |
| 142 return new DivElement()..classes = ['class-tree-item'] | 146 return new DivElement() |
| 143 ..children = [ | 147 ..classes = ['class-tree-item'] |
| 144 new SpanElement()..classes = ['lines'], | 148 ..children = [ |
| 145 new ButtonElement()..classes = ['expander'] | 149 new SpanElement()..classes = ['lines'], |
| 146 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), | 150 new ButtonElement() |
| 147 new SpanElement()..classes = ['name'] | 151 ..classes = ['expander'] |
| 148 ]; | 152 ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
| 153 new SpanElement()..classes = ['name'] |
| 154 ]; |
| 149 } | 155 } |
| 150 | 156 |
| 151 void _update(HtmlElement el, M.Class cls, int index) { | 157 void _update(HtmlElement el, M.Class cls, int index) { |
| 152 virtualTreeUpdateLines(el.children[0], index); | 158 virtualTreeUpdateLines(el.children[0], index); |
| 153 if (cls.subclasses.isEmpty) { | 159 if (cls.subclasses.isEmpty) { |
| 154 el.children[1].text = ''; | 160 el.children[1].text = ''; |
| 155 } else { | 161 } else { |
| 156 el.children[1].text = _tree.isExpanded(cls) ? '▼' : '►'; | 162 el.children[1].text = _tree.isExpanded(cls) ? '▼' : '►'; |
| 157 } | 163 } |
| 158 el.children[2].children = [ | 164 el.children[2].children = [ |
| 159 new ClassRefElement(_isolate, cls, queue: _r.queue) | 165 new ClassRefElement(_isolate, cls, queue: _r.queue) |
| 160 ]; | 166 ]; |
| 161 if (_mixins[cls.id] != null) { | 167 if (_mixins[cls.id] != null) { |
| 162 el.children[2].children.addAll(_createMixins(_mixins[cls.id])); | 168 el.children[2].children.addAll(_createMixins(_mixins[cls.id])); |
| 163 } | 169 } |
| 164 } | 170 } |
| 165 | 171 |
| 166 List<Element> _createMixins(List<M.Instance> types) { | 172 List<Element> _createMixins(List<M.Instance> types) { |
| 167 final children = types.expand((type) => [ | 173 final children = types |
| 168 new SpanElement()..text = ', ', | 174 .expand((type) => [ |
| 169 type.typeClass == null | 175 new SpanElement()..text = ', ', |
| 170 ? (new SpanElement()..text = type.name.split('<').first) | 176 type.typeClass == null |
| 171 : new ClassRefElement(_isolate, type.typeClass, queue: _r.queue) | 177 ? (new SpanElement()..text = type.name.split('<').first) |
| 172 ]).toList(); | 178 : new ClassRefElement(_isolate, type.typeClass, |
| 179 queue: _r.queue) |
| 180 ]) |
| 181 .toList(); |
| 173 children.first.text = ' with '; | 182 children.first.text = ' with '; |
| 174 return children; | 183 return children; |
| 175 } | 184 } |
| 176 | 185 |
| 177 Iterable<M.Class> _children(M.Class cls) { | 186 Iterable<M.Class> _children(M.Class cls) { |
| 178 return _subclasses[cls.id]; | 187 return _subclasses[cls.id]; |
| 179 } | 188 } |
| 180 } | 189 } |
| OLD | NEW |