Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_view_element; | 5 library class_view_element; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'observatory_element.dart'; | 8 import 'dart:html'; |
| 9 import 'sample_buffer_control.dart'; | |
| 10 import 'stack_trace_tree_config.dart'; | |
| 11 import 'cpu_profile/virtual_tree.dart'; | |
| 12 import 'package:observatory/heap_snapshot.dart'; | |
| 13 import 'package:observatory/elements.dart'; | |
| 14 import 'package:observatory/models.dart' as M; | 9 import 'package:observatory/models.dart' as M; |
| 15 import 'package:observatory/service.dart'; | 10 import 'package:observatory/src/elements/class_allocation_profile.dart'; |
| 16 import 'package:observatory/repositories.dart'; | 11 import 'package:observatory/src/elements/class_instances.dart'; |
| 17 import 'package:polymer/polymer.dart'; | 12 import 'package:observatory/src/elements/class_ref.dart'; |
| 18 | 13 import 'package:observatory/src/elements/curly_block.dart'; |
| 19 @CustomTag('class-view') | 14 import 'package:observatory/src/elements/error_ref.dart'; |
| 20 class ClassViewElement extends ObservatoryElement { | 15 import 'package:observatory/src/elements/eval_box.dart'; |
| 21 @published Class cls; | 16 import 'package:observatory/src/elements/field_ref.dart'; |
| 22 @observable ServiceMap instances; | 17 import 'package:observatory/src/elements/function_ref.dart'; |
| 23 @observable int reachableBytes; | 18 import 'package:observatory/src/elements/helpers/any_ref.dart'; |
| 24 @observable int retainedBytes; | 19 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; |
| 25 @observable ObservableList mostRetained; | 20 import 'package:observatory/src/elements/helpers/tag.dart'; |
| 26 SampleBufferControlElement sampleBufferControlElement; | 21 import 'package:observatory/src/elements/instance_ref.dart'; |
| 27 StackTraceTreeConfigElement stackTraceTreeConfigElement; | 22 import 'package:observatory/src/elements/library_ref.dart'; |
| 28 CpuProfileVirtualTreeElement cpuProfileTreeElement; | 23 import 'package:observatory/src/elements/nav/bar.dart'; |
| 29 ClassSampleProfileRepository repository = new ClassSampleProfileRepository(); | 24 import 'package:observatory/src/elements/nav/class_menu.dart'; |
| 30 | 25 import 'package:observatory/src/elements/nav/isolate_menu.dart'; |
| 26 import 'package:observatory/src/elements/nav/menu.dart'; | |
| 27 import 'package:observatory/src/elements/nav/notify.dart'; | |
| 28 import 'package:observatory/src/elements/nav/refresh.dart'; | |
| 29 import 'package:observatory/src/elements/nav/top_menu.dart'; | |
| 30 import 'package:observatory/src/elements/nav/vm_menu.dart'; | |
| 31 import 'package:observatory/src/elements/object_common.dart'; | |
| 32 import 'package:observatory/src/elements/source_inset.dart'; | |
| 33 import 'package:observatory/src/elements/source_link.dart'; | |
| 34 import 'package:observatory/src/elements/view_footer.dart'; | |
| 35 | |
| 36 class ClassViewElement extends HtmlElement implements Renderable { | |
| 37 static const tag = const Tag<ClassViewElement>('class-view', | |
| 38 dependencies: const [ | |
| 39 ClassInstancesElement.tag, | |
| 40 ClassRefElement.tag, | |
| 41 CurlyBlockElement.tag, | |
| 42 ErrorRefElement.tag, | |
| 43 EvalBoxElement.tag, | |
| 44 FieldRefElement.tag, | |
| 45 FunctionRefElement.tag, | |
| 46 InstanceRefElement.tag, | |
| 47 LibraryRefElement.tag, | |
| 48 NavBarElement.tag, | |
| 49 NavClassMenuElement.tag, | |
| 50 NavTopMenuElement.tag, | |
| 51 NavVMMenuElement.tag, | |
| 52 NavIsolateMenuElement.tag, | |
| 53 NavMenuElement.tag, | |
| 54 NavRefreshElement.tag, | |
| 55 NavNotifyElement.tag, | |
| 56 ObjectCommonElement.tag, | |
| 57 SourceInsetElement.tag, | |
| 58 SourceLinkElement.tag, | |
| 59 ViewFooterElement.tag | |
| 60 ]); | |
| 61 | |
| 62 RenderingScheduler<ClassViewElement> _r; | |
| 63 | |
| 64 Stream<RenderedEvent<ClassViewElement>> get onRendered => _r.onRendered; | |
| 65 | |
| 66 M.VM _vm; | |
| 67 M.IsolateRef _isolate; | |
| 68 M.EventRepository _events; | |
| 69 M.NotificationRepository _notifications; | |
| 70 M.Class _cls; | |
| 71 M.ClassRepository _classes; | |
| 72 M.RetainedSizeRepository _retainedSizes; | |
| 73 M.ReachableSizeRepository _reachableSizes; | |
| 74 M.InboundReferencesRepository _references; | |
| 75 M.RetainingPathRepository _retainingPaths; | |
| 76 M.StronglyReachableInstancesRepository _stronglyReachableInstances; | |
| 77 M.TopRetainingInstancesRepository _topRetainedInstances; | |
| 78 M.FieldRepository _fields; | |
| 79 M.ScriptRepository _scripts; | |
| 80 M.InstanceRepository _instances; | |
| 81 M.EvalRepository _eval; | |
| 82 M.ClassSampleProfileRepository _profiles; | |
| 83 Iterable<M.Field> _classFields; | |
| 84 | |
| 85 | |
| 86 M.VMRef get vm => _vm; | |
| 87 M.IsolateRef get isolate => _isolate; | |
| 88 M.NotificationRepository get notifications => _notifications; | |
| 89 M.Class get cls => _cls; | |
| 90 | |
| 91 factory ClassViewElement(M.VM vm, M.IsolateRef isolate, M.Class cls, | |
| 92 M.EventRepository events, | |
| 93 M.NotificationRepository notifications, | |
| 94 M.ClassRepository classes, | |
| 95 M.RetainedSizeRepository retainedSizes, | |
| 96 M.ReachableSizeRepository reachableSizes, | |
| 97 M.InboundReferencesRepository references, | |
| 98 M.RetainingPathRepository retainingPaths, | |
| 99 M.FieldRepository fields, | |
| 100 M.ScriptRepository scripts, | |
| 101 M.InstanceRepository instances, | |
| 102 M.EvalRepository eval, | |
| 103 M.StronglyReachableInstancesRepository stronglyReachable, | |
| 104 M.TopRetainingInstancesRepository topRetained, | |
| 105 M.ClassSampleProfileRepository profiles, | |
| 106 {RenderingQueue queue}) { | |
| 107 assert(vm != null); | |
| 108 assert(isolate != null); | |
| 109 assert(events != null); | |
| 110 assert(notifications != null); | |
| 111 assert(cls != null); | |
| 112 assert(classes != null); | |
| 113 assert(retainedSizes != null); | |
| 114 assert(reachableSizes != null); | |
| 115 assert(references != null); | |
| 116 assert(retainingPaths != null); | |
| 117 assert(fields != null); | |
| 118 assert(scripts != null); | |
| 119 assert(instances != null); | |
| 120 assert(eval != null); | |
| 121 assert(stronglyReachable != null); | |
| 122 assert(topRetained != null); | |
| 123 assert(profiles != null); | |
| 124 ClassViewElement e = document.createElement(tag.name); | |
| 125 e._r = new RenderingScheduler(e, queue: queue); | |
| 126 e._vm = vm; | |
| 127 e._isolate = isolate; | |
| 128 e._events = events; | |
| 129 e._notifications = notifications; | |
| 130 e._cls = cls; | |
| 131 e._classes = classes; | |
| 132 e._retainedSizes = retainedSizes; | |
| 133 e._reachableSizes = reachableSizes; | |
| 134 e._references = references; | |
| 135 e._retainingPaths = retainingPaths; | |
| 136 e._fields = fields; | |
| 137 e._scripts = scripts; | |
| 138 e._instances = instances; | |
| 139 e._eval = eval; | |
| 140 e._stronglyReachableInstances = stronglyReachable; | |
| 141 e._topRetainedInstances = topRetained; | |
| 142 e._profiles = profiles; | |
| 143 return e; | |
| 144 } | |
| 31 | 145 |
| 32 ClassViewElement.created() : super.created(); | 146 ClassViewElement.created() : super.created(); |
| 33 | 147 |
| 34 Future<ServiceObject> evaluate(String expression) { | 148 @override |
| 35 return cls.evaluate(expression); | 149 attached() { |
| 36 } | |
| 37 | |
| 38 Future<ServiceObject> reachable(var limit) { | |
| 39 return cls.isolate.getInstances(cls, limit).then((ServiceMap obj) { | |
| 40 instances = obj; | |
| 41 }); | |
| 42 } | |
| 43 | |
| 44 Future retainedToplist(var limit) async { | |
| 45 final raw = await cls.isolate.fetchHeapSnapshot(true).last; | |
| 46 final snapshot = new HeapSnapshot(); | |
| 47 await snapshot.loadProgress(cls.isolate, raw).last; | |
| 48 final most = await Future.wait(snapshot.getMostRetained(cls.isolate, | |
| 49 classId: cls.vmCid , | |
| 50 limit: 10)); | |
| 51 mostRetained = new ObservableList.from(most); | |
| 52 } | |
| 53 | |
| 54 // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link". | |
| 55 Future<ServiceObject> reachableSize(var dummy) { | |
| 56 return cls.isolate.getReachableSize(cls).then((Instance obj) { | |
| 57 reachableBytes = int.parse(obj.valueAsString); | |
| 58 }); | |
| 59 } | |
| 60 | |
| 61 Future<ServiceObject> retainedSize(var dummy) { | |
| 62 return cls.isolate.getRetainedSize(cls).then((Instance obj) { | |
| 63 retainedBytes = int.parse(obj.valueAsString); | |
| 64 }); | |
| 65 } | |
| 66 | |
| 67 void attached() { | |
| 68 super.attached(); | 150 super.attached(); |
| 69 cls.fields.forEach((field) => field.reload()); | 151 _r.enable(); |
| 70 } | 152 _loadAdditionalData(); |
| 71 | 153 } |
| 72 Future refresh() async { | 154 |
| 73 instances = null; | 155 @override |
| 74 retainedBytes = null; | 156 detached() { |
| 75 mostRetained = null; | 157 super.detached(); |
| 76 await cls.reload(); | 158 _r.disable(notify: true); |
| 77 await Future.wait(cls.fields.map((field) => field.reload())); | 159 children = []; |
| 78 } | 160 } |
| 79 | 161 |
| 80 M.SampleProfileTag _tag = M.SampleProfileTag.none; | 162 ObjectCommonElement _common; |
| 81 | 163 ClassInstancesElement _classInstances; |
| 82 Future refreshAllocationProfile() async { | 164 bool _loadProfile = false; |
| 83 shadowRoot.querySelector('#sampleBufferControl').children = const []; | 165 |
| 84 shadowRoot.querySelector('#stackTraceTreeConfig').children = const []; | 166 void render() { |
| 85 shadowRoot.querySelector('#cpuProfileTree').children = const []; | 167 _common = _common ?? new ObjectCommonElement(_isolate, _cls, _retainedSizes, |
| 86 final stream = repository.get(cls, _tag); | 168 _reachableSizes, _references, _retainingPaths, _instances, |
| 87 var progress = (await stream.first).progress; | 169 queue: _r.queue); |
| 88 shadowRoot.querySelector('#sampleBufferControl')..children = [ | 170 _classInstances = _classInstances ?? new ClassInstancesElement(_isolate, |
| 89 new SampleBufferControlElement(progress, stream, queue: app.queue, | 171 _cls, _retainedSizes, _reachableSizes, _stronglyReachableInstances, |
| 90 selectedTag: _tag) | 172 _topRetainedInstances, _instances, queue: _r.queue); |
| 91 ..onTagChange.listen((e) { | 173 var header = ''; |
| 92 _tag = e.element.selectedTag; | 174 if (_cls.isAbstract) { |
| 93 refreshAllocationProfile(); | 175 header += 'abstract '; |
| 94 }) | 176 } |
| 177 if (_cls.isPatch) { | |
| 178 header += 'patch '; | |
| 179 } | |
| 180 if (_cls.mixin != null) { | |
|
rmacnak
2016/08/31 23:51:39
I'd remove this. If class's mixin isn't null, that
cbernaschina
2016/09/01 00:04:07
Done.
| |
| 181 header += 'mixin '; | |
| 182 } | |
| 183 children = [ | |
| 184 new NavBarElement(queue: _r.queue) | |
| 185 ..children = [ | |
| 186 new NavTopMenuElement(queue: _r.queue), | |
| 187 new NavVMMenuElement(_vm, _events, queue: _r.queue), | |
| 188 new NavIsolateMenuElement(_isolate, _events, queue: _r.queue), | |
| 189 new NavClassMenuElement(_isolate, _cls, queue: _r.queue), | |
| 190 new NavRefreshElement(label: 'Refresh Allocation Profile', | |
| 191 queue: _r.queue) | |
| 192 ..onRefresh.listen((e) { | |
| 193 e.element.disabled = true; | |
| 194 _loadProfile = true; | |
| 195 _r.dirty(); | |
| 196 }), | |
| 197 new NavRefreshElement(queue: _r.queue) | |
| 198 ..onRefresh.listen((e) { | |
| 199 e.element.disabled = true; | |
| 200 _common = null; | |
| 201 _classInstances = null; | |
| 202 _fieldsExpanded = null; | |
| 203 _functionsExpanded = null; | |
| 204 _refresh(); | |
| 205 }), | |
| 206 new NavNotifyElement(_notifications, queue: _r.queue) | |
| 207 ], | |
| 208 new DivElement()..classes = ['content-centered-big'] | |
| 209 ..children = [ | |
| 210 new HeadingElement.h2()..text = '$header class ${_cls.name}', | |
| 211 new HRElement(), | |
| 212 _common, | |
| 213 new BRElement(), | |
| 214 new DivElement()..classes = ['memberList'] | |
| 215 ..children = _createMembers(), | |
| 216 new DivElement() | |
| 217 ..children = _cls.error == null | |
| 218 ? const [] | |
| 219 : [ | |
| 220 new HRElement(), | |
| 221 new ErrorRefElement(_cls.error, queue: _r.queue) | |
| 222 ], | |
| 223 new HRElement(), | |
| 224 new EvalBoxElement(_isolate, _cls, _instances, _eval, | |
| 225 queue: _r.queue), | |
| 226 new HRElement(), | |
| 227 new HeadingElement.h2()..text = 'Fields & Functions', | |
| 228 new DivElement()..classes = ['memberList'] | |
| 229 ..children = _createElements(), | |
| 230 new HRElement(), | |
| 231 new HeadingElement.h2()..text = 'Instances', | |
| 232 new DivElement() | |
| 233 ..children = _cls.hasAllocations | |
| 234 ? [_classInstances] | |
| 235 : const [], | |
| 236 new HRElement(), | |
| 237 new HeadingElement.h2()..text = 'Allocations', | |
| 238 new DivElement()..classes = ['memberList'] | |
| 239 ..children = [ | |
| 240 new DivElement()..classes = ['memberName'] | |
| 241 ..text = 'Tracing allocations?» ', | |
| 242 new DivElement()..classes = ['memberValue'] | |
| 243 ..children = _cls.traceAllocations | |
| 244 ? [ | |
| 245 new SpanElement()..text = 'Yes ', | |
| 246 new ButtonElement()..text = 'disable' | |
| 247 ..onClick.listen((e) async { | |
| 248 e.target.disabled = true; | |
| 249 await _profiles.disable(_isolate, _cls); | |
| 250 _loadProfile = true; | |
| 251 _refresh(); | |
| 252 }) | |
| 253 ] | |
| 254 : [ | |
| 255 new SpanElement()..text = 'No ', | |
| 256 new ButtonElement()..text = 'enable' | |
| 257 ..onClick.listen((e) async { | |
| 258 e.target.disabled = true; | |
| 259 await _profiles.enable(_isolate, _cls); | |
| 260 _refresh(); | |
| 261 }) | |
| 262 ] | |
| 263 ], | |
| 264 new DivElement() | |
| 265 ..children = _loadProfile | |
| 266 ? [new ClassAllocationProfileElement(_isolate, _cls, _profiles, | |
| 267 queue: _r.queue)] | |
| 268 : const [], | |
| 269 new DivElement() | |
| 270 ..children = _cls.location != null | |
| 271 ? [new HRElement(), | |
| 272 new SourceInsetElement(_isolate, _cls.location, _scripts, | |
| 273 _instances, _events, queue: _r.queue)] | |
| 274 : const [], | |
| 275 new HRElement(), | |
| 276 new ViewFooterElement(queue: _r.queue) | |
| 277 ] | |
| 95 ]; | 278 ]; |
| 96 if (M.isSampleProcessRunning(progress.status)) { | 279 } |
| 97 progress = (await stream.last).progress; | 280 |
| 98 } | 281 bool _fieldsExpanded; |
| 99 if (progress.status == M.SampleProfileLoadingStatus.loaded) { | 282 bool _functionsExpanded; |
| 100 shadowRoot.querySelector('#stackTraceTreeConfig')..children = [ | 283 |
| 101 new StackTraceTreeConfigElement( | 284 List<Element> _createMembers() { |
| 102 queue: app.queue) | 285 final members = <Element>[]; |
| 103 ..showFilter = false | 286 if (_cls.library != null) { |
| 104 ..onModeChange.listen((e) { | 287 members.add( |
| 105 cpuProfileTreeElement.mode = e.element.mode; | 288 new DivElement()..classes = ['memberItem'] |
| 106 }) | 289 ..children = [ |
| 107 ..onDirectionChange.listen((e) { | 290 new DivElement()..classes = ['memberName'] |
| 108 cpuProfileTreeElement.direction = e.element.direction; | 291 ..text = 'library', |
| 109 }) | 292 new DivElement()..classes = ['memberValue'] |
| 110 ]; | 293 ..children = [ |
| 111 shadowRoot.querySelector('#cpuProfileTree')..children = [ | 294 new LibraryRefElement(_isolate, _cls.library, queue: _r.queue) |
| 112 cpuProfileTreeElement = new CpuProfileVirtualTreeElement(cls.isolate, | 295 ] |
| 113 progress.profile, queue: app.queue) | 296 ] |
| 114 ]; | 297 ); |
| 115 } | 298 } |
| 116 } | 299 if (_cls.location != null) { |
| 117 | 300 members.add( |
| 118 Future toggleAllocationTrace() { | 301 new DivElement()..classes = ['memberItem'] |
| 119 if (cls == null) { | 302 ..children = [ |
| 120 return new Future(refresh); | 303 new DivElement()..classes = ['memberName'] |
| 121 } | 304 ..text = 'script', |
| 122 if (cls.traceAllocations) { | 305 new DivElement()..classes = ['memberValue'] |
| 123 refreshAllocationProfile(); | 306 ..children = [ |
| 124 } | 307 new SourceLinkElement(_isolate, _cls.location, _scripts, |
| 125 return cls.setTraceAllocations(!cls.traceAllocations).whenComplete(refresh); | 308 queue: _r.queue) |
| 309 ] | |
| 310 ] | |
| 311 ); | |
| 312 } | |
| 313 if (_cls.superclass != null) { | |
| 314 members.add( | |
| 315 new DivElement()..classes = ['memberItem'] | |
| 316 ..children = [ | |
| 317 new DivElement()..classes = ['memberName'] | |
| 318 ..text = 'superclass', | |
| 319 new DivElement()..classes = ['memberValue'] | |
| 320 ..children = [ | |
| 321 new ClassRefElement(_isolate, _cls.superclass, queue: _r.queue) | |
| 322 ] | |
| 323 ] | |
| 324 ); | |
| 325 } | |
| 326 if (_cls.superType != null) { | |
| 327 members.add( | |
| 328 new DivElement()..classes = ['memberItem'] | |
| 329 ..children = [ | |
| 330 new DivElement()..classes = ['memberName'] | |
| 331 ..text = 'supertype', | |
| 332 new DivElement()..classes = ['memberValue'] | |
| 333 ..children = [ | |
| 334 new InstanceRefElement(_isolate, _cls.superType, _instances, | |
| 335 queue: _r.queue) | |
| 336 ] | |
| 337 ] | |
| 338 ); | |
| 339 } | |
| 340 if (cls.mixin != null) { | |
| 341 members.add( | |
| 342 new DivElement()..classes = ['memberItem'] | |
| 343 ..children = [ | |
| 344 new DivElement()..classes = ['memberName'] | |
| 345 ..text = 'mixin', | |
| 346 new DivElement()..classes = ['memberValue'] | |
| 347 ..children = [ | |
| 348 new InstanceRefElement(_isolate, _cls.mixin, _instances, | |
| 349 queue: _r.queue) | |
| 350 ] | |
| 351 ] | |
| 352 ); | |
| 353 } | |
| 354 if (_cls.subclasses.length > 0) { | |
| 355 members.add( | |
| 356 new DivElement()..classes = ['memberItem'] | |
| 357 ..children = [ | |
| 358 new DivElement()..classes = ['memberName'] | |
| 359 ..text = 'extended by', | |
| 360 new DivElement()..classes = ['memberValue'] | |
| 361 ..children = (_cls.subclasses.expand((subcls) => [ | |
| 362 new ClassRefElement(_isolate, subcls, queue: _r.queue), | |
| 363 new SpanElement()..text = ', ' | |
| 364 ]).toList()..removeLast()) | |
| 365 ] | |
| 366 ); | |
| 367 } | |
| 368 | |
| 369 members.add(new BRElement()); | |
| 370 | |
| 371 if (_cls.interfaces.length > 0) { | |
| 372 members.add( | |
|
rmacnak
2016/08/31 23:51:39
This pattern seems to get repeated a lot in many o
cbernaschina
2016/09/01 00:04:07
Acknowledged.
| |
| 373 new DivElement()..classes = ['memberItem'] | |
| 374 ..children = [ | |
| 375 new DivElement()..classes = ['memberName'] | |
| 376 ..text = 'implements', | |
| 377 new DivElement()..classes = ['memberValue'] | |
| 378 ..children = (_cls.interfaces.expand((interf) => [ | |
| 379 new InstanceRefElement(_isolate, interf, _instances, | |
| 380 queue: _r.queue), | |
| 381 new SpanElement()..text = ', ' | |
| 382 ]).toList()..removeLast()) | |
| 383 ] | |
| 384 ); | |
| 385 } | |
| 386 if (_cls.name != _cls.vmName) { | |
| 387 members.add( | |
| 388 new DivElement()..classes = ['memberItem'] | |
| 389 ..children = [ | |
| 390 new DivElement()..classes = ['memberName'] | |
| 391 ..text = 'vm name', | |
| 392 new DivElement()..classes = ['memberValue'] | |
| 393 ..text = '${_cls.vmName}' | |
| 394 ] | |
| 395 ); | |
| 396 } | |
| 397 return members; | |
| 398 } | |
| 399 | |
| 400 List<Element> _createElements() { | |
| 401 final members = <Element>[]; | |
| 402 if (_classFields != null && _classFields.isNotEmpty) { | |
| 403 final fields = _classFields.toList(); | |
| 404 _fieldsExpanded = _fieldsExpanded ?? (fields.length <= 8); | |
| 405 members.add( | |
| 406 new DivElement()..classes = ['memberItem'] | |
| 407 ..children = [ | |
| 408 new DivElement()..classes = ['memberName'] | |
| 409 ..text = 'fields ${fields.length}', | |
| 410 new DivElement()..classes = ['memberValue'] | |
| 411 ..children =[ | |
| 412 new CurlyBlockElement(expanded: _fieldsExpanded) | |
| 413 ..onToggle.listen((e) => _fieldsExpanded = e.control.expanded) | |
| 414 ..children = [ | |
| 415 new DivElement()..classes = ['memberList'] | |
| 416 ..children = (fields.map((f) => | |
| 417 new DivElement()..classes = ['memberItem'] | |
| 418 ..children = [ | |
| 419 new DivElement()..classes = ['memberName'] | |
| 420 ..children =[ | |
| 421 new FieldRefElement(_isolate, f, _instances, | |
| 422 queue: _r.queue) | |
| 423 ], | |
| 424 new DivElement()..classes = ['memberValue'] | |
| 425 ..children = [ | |
| 426 anyRef(_isolate, f.staticValue, _instances, | |
| 427 queue: _r.queue) | |
| 428 ] | |
| 429 ] | |
| 430 ).toList()) | |
| 431 ] | |
| 432 ] | |
| 433 ] | |
| 434 ); | |
| 435 } | |
| 436 | |
| 437 if (_cls.functions.isNotEmpty) { | |
| 438 final functions = _cls.functions.toList(); | |
| 439 _functionsExpanded = _functionsExpanded ?? (functions.length <= 8); | |
| 440 members.add( | |
| 441 new DivElement()..classes = ['memberItem'] | |
| 442 ..children = [ | |
| 443 new DivElement()..classes = ['memberName'] | |
| 444 ..text = 'functions (${functions.length})', | |
| 445 new DivElement()..classes = ['memberValue'] | |
| 446 ..children =[ | |
| 447 new CurlyBlockElement(expanded: _functionsExpanded) | |
| 448 ..onToggle.listen((e) => | |
| 449 _functionsExpanded = e.control.expanded) | |
| 450 ..children = (functions.map((f) => | |
| 451 new DivElement()..classes = ['indent'] | |
| 452 ..children = [ | |
| 453 new FunctionRefElement(_isolate, f, queue: _r.queue) | |
| 454 ] | |
| 455 ).toList()) | |
| 456 ] | |
| 457 ] | |
| 458 ); | |
| 459 } | |
| 460 return members; | |
| 461 } | |
| 462 | |
| 463 Future _refresh() async { | |
| 464 _cls = await _classes.get(_isolate, _cls.id); | |
| 465 await _loadAdditionalData(); | |
| 466 _r.dirty(); | |
| 467 } | |
| 468 | |
| 469 Future _loadAdditionalData() async { | |
| 470 _classFields = await Future.wait(_cls.fields.map((f) | |
| 471 => _fields.get(_isolate, f.id))); | |
| 472 _r.dirty(); | |
| 126 } | 473 } |
| 127 } | 474 } |
| OLD | NEW |