Index: runtime/observatory/lib/src/elements/class_tree.dart |
diff --git a/runtime/observatory/lib/src/elements/class_tree.dart b/runtime/observatory/lib/src/elements/class_tree.dart |
index 16f6928fbd72a7b193f0445f2b021e5909b929b9..cb927b272e16b5aa9106a0093ab1035e36f64d92 100644 |
--- a/runtime/observatory/lib/src/elements/class_tree.dart |
+++ b/runtime/observatory/lib/src/elements/class_tree.dart |
@@ -4,14 +4,193 @@ |
library class_tree_element; |
-import 'observatory_element.dart'; |
-import 'dart:async'; |
import 'dart:html'; |
-import 'package:logging/logging.dart'; |
-import 'package:observatory/app.dart'; |
-import 'package:observatory/service.dart'; |
-import 'package:polymer/polymer.dart'; |
+import 'dart:async'; |
+import 'package:observatory/models.dart' as M; |
+import 'package:observatory/src/elements/class_ref.dart'; |
+import 'package:observatory/src/elements/containers/virtual_tree.dart'; |
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
+import 'package:observatory/src/elements/helpers/tag.dart'; |
+import 'package:observatory/src/elements/helpers/uris.dart'; |
+import 'package:observatory/src/elements/nav/bar.dart'; |
+import 'package:observatory/src/elements/nav/isolate_menu.dart'; |
+import 'package:observatory/src/elements/nav/menu.dart'; |
+import 'package:observatory/src/elements/nav/notify.dart'; |
+import 'package:observatory/src/elements/nav/top_menu.dart'; |
+import 'package:observatory/src/elements/nav/vm_menu.dart'; |
+ |
+ |
+class ClassTreeElement extends HtmlElement implements Renderable{ |
+ static const tag = const Tag<ClassTreeElement>('class-tree', |
+ dependencies: const [ClassRefElement.tag, |
+ NavBarElement.tag, |
+ NavIsolateMenuElement.tag, |
+ NavMenuElement.tag, |
+ NavNotifyElement.tag, |
+ NavTopMenuElement.tag, |
+ NavVMMenuElement.tag]); |
+ |
+ RenderingScheduler _r; |
+ |
+ Stream<RenderedEvent<ClassTreeElement>> get onRendered => _r.onRendered; |
+ |
+ M.VMRef _vm; |
+ M.IsolateRef _isolate; |
+ M.EventRepository _events; |
+ M.NotificationRepository _notifications; |
+ M.ClassRepository _classes; |
+ M.InstanceRepository _instances; |
+ M.Class _object; |
+ final _subclasses = <String, Iterable<M.Class>>{}; |
+ final _mixins = <String, List<M.Class>>{}; |
+ |
+ factory ClassTreeElement(M.VMRef vm, M.IsolateRef isolate, |
+ M.EventRepository events, |
+ M.NotificationRepository notifications, |
+ M.ClassRepository classes, |
+ M.InstanceRepository instances, |
+ {RenderingQueue queue}) { |
+ assert(vm != null); |
+ assert(isolate != null); |
+ assert(events != null); |
+ assert(notifications != null); |
+ assert(classes != null); |
+ assert(instances != null); |
+ ClassTreeElement e = document.createElement(tag.name); |
+ e._r = new RenderingScheduler(e, queue: queue); |
+ e._vm = vm; |
+ e._isolate = isolate; |
+ e._events = events; |
+ e._notifications = notifications; |
+ e._classes = classes; |
+ e._instances = instances; |
+ return e; |
+ } |
+ |
+ ClassTreeElement.created() : super.created(); |
+ |
+ @override |
+ void attached() { |
+ super.attached(); |
+ _refresh(); |
+ _r.enable(); |
+ } |
+ |
+ @override |
+ void detached() { |
+ super.detached(); |
+ children = []; |
+ _r.disable(notify: true); |
+ } |
+ |
+ VirtualTreeElement _tree; |
+ |
+ void render() { |
+ children = [ |
+ new NavBarElement(queue: _r.queue) |
+ ..children = [ |
+ new NavTopMenuElement(queue: _r.queue), |
+ new NavVMMenuElement(_vm, _events, queue: _r.queue), |
+ new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), |
+ new NavMenuElement('class hierarchy', link: Uris.classTree(_isolate), |
+ last: true, queue: _r.queue), |
+ new NavNotifyElement(_notifications, queue: _r.queue) |
+ ], |
+ new DivElement() |
+ ..classes = ['content-centered'] |
+ ..children = [ |
+ new HeadingElement.h1()..text = 'Class Hierarchy', |
+ new BRElement(), new HRElement(), |
+ _object == null ? (new HeadingElement.h2()..text = 'Loading...') |
+ : _createTree() |
+ ] |
+ ]; |
+ } |
+ |
+ Element _createTree() { |
+ _tree = new VirtualTreeElement(_create, _update, _children, |
+ items: [_object], queue: _r.queue); |
+ _tree.expand(_object, autoExpandWholeTree: true); |
+ return _tree; |
+ } |
+ |
+ Future _refresh() async { |
+ _object = null; |
+ _subclasses.clear(); |
+ _mixins.clear(); |
+ _object = await _register(await _classes.getObject()); |
+ _r.dirty(); |
+ } |
+ Future<M.Class> _register(M.Class cls) async { |
+ _subclasses[cls.id] = await Future.wait( |
+ (await Future.wait(cls.subclasses.map(_getActualChildrens))) |
+ .expand((f) => f) |
+ .map(_register) |
+ ); |
+ return cls; |
+ } |
+ |
+ Future<Iterable<M.Class>> _getActualChildrens(M.ClassRef ref) async { |
+ var cls = await _classes.get(ref.id); |
+ if (cls.isPatch) { |
+ return const []; |
+ } |
+ if (cls.mixin == null) { |
+ return [cls]; |
+ } |
+ var mixin = await _instances.get(cls.mixin.id); |
+ return (await Future.wait(cls.subclasses.map(_getActualChildrens))) |
+ .expand((f) => f) |
+ ..forEach((subcls) { |
+ // non canonical type. |
+ if (mixin.typeClass == null) { |
+ return; |
+ } |
+ _mixins[subcls.id] = (_mixins[subcls.id] ?? [])..add(mixin.typeClass); |
+ }); |
+ } |
+ |
+ static Element _create(toggle) { |
+ return new DivElement()..classes = ['class-tree-item'] |
+ ..children = [ |
+ new SpanElement()..classes = ['lines'], |
+ new SpanElement()..classes = ['expander'] |
+ ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), |
+ new SpanElement()..classes = ['name'] |
+ ]; |
+ } |
+ |
+ void _update(HtmlElement el, M.Class cls, int index) { |
+ virtualTreeUpdateLines(el.children[0], index); |
+ if (cls.subclasses.isEmpty) { |
+ el.children[1].text = ''; |
+ } else { |
+ el.children[1].text = _tree.isExpanded(cls) ? '▼' : '►'; |
+ } |
+ el.children[2].children = [ |
+ new ClassRefElement(_isolate, cls, queue: _r.queue) |
+ ]; |
+ if (_mixins[cls.id] != null) { |
+ el.children[2].children.addAll(_createMixins(_mixins[cls.id])); |
+ } |
+ } |
+ |
+ List<Element> _createMixins(List<M.Class> classes) { |
+ final children = classes.expand((cls) => [ |
+ new SpanElement()..text = ', ', |
+ new ClassRefElement(_isolate, cls, queue: _r.queue) |
+ ]).toList(); |
+ children.first.text = ' width '; |
+ return children; |
+ } |
+ |
+ Iterable<M.Class> _children(M.Class cls) { |
+ return _subclasses[cls.id]; |
+ } |
+} |
+ |
+/* |
Cutch
2016/08/05 13:23:18
remove deleted code
cbernaschina
2016/08/05 17:16:46
Done.
|
class ClassTreeRow extends TableTreeRow { |
@reflectable final Isolate isolate; |
@reflectable final Class cls; |
@@ -151,3 +330,45 @@ class ClassTreeElement extends ObservatoryElement { |
notifyPropertyChange(#tree, null, tree); |
} |
} |
+*/ |
+ |
+/* |
+<polymer-element name="class-tree"> |
+ <template> |
+ <link rel="stylesheet" href="css/shared.css"> |
+ <style> |
+ .table { |
+ border-spacing: 0px; |
+ width: 100%; |
+ margin-bottom: 20px |
+ vertical-align: middle; |
+ } |
+ |
+ tr { |
+ background-color: #FFFFFF; |
+ } |
+ |
+ tr:hover { |
+ background-color: #FAFAFA; |
+ } |
+ |
+ th { |
+ text-align: left; |
+ } |
+ </style> |
+ <nav-bar> |
+ <top-nav-menu></top-nav-menu> |
+ <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu> |
+ <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu> |
+ <nav-menu link="{{ makeLink('/class-tree', isolate) }}" anchor="class hierarchy" last="{{ true }}"></nav-menu> |
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify> |
+ </nav-bar> |
+ <div class="content-centered"> |
+ <h1>Class Hierarchy</h1> |
+ <table id="tableTree" class="table"> |
+ <tbody id="tableTreeBody"></tbody> |
+ </table> |
+ </div> |
+ </template> |
+</polymer-element> |
+ */ |