| 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 part of app; | 5 part of app; |
| 6 | 6 |
| 7 /// A [Pane] controls the user interface of Observatory. At any given time | |
| 8 /// one pane will be the current pane. Panes are registered at startup. | |
| 9 /// When the user navigates within the application, each pane is asked if it | |
| 10 /// can handle the current location, the first pane to say yes, wins. | |
| 11 abstract class Pane extends Observable { | |
| 12 final ObservatoryApplication app; | |
| 13 | |
| 14 @observable ObservatoryElement element; | |
| 15 | |
| 16 Pane(this.app); | |
| 17 | |
| 18 /// Called when the pane is installed, this callback must initialize | |
| 19 /// [element]. | |
| 20 void onInstall(); | |
| 21 | |
| 22 /// Called when the pane is uninstalled, this callback must clear | |
| 23 /// [element]. | |
| 24 void onUninstall() { | |
| 25 element = null; | |
| 26 } | |
| 27 | |
| 28 /// Called when the pane should update its state based on [url]. | |
| 29 /// NOTE: Only called when the pane is installed. | |
| 30 void visit(String url); | |
| 31 | |
| 32 /// Called to test whether this pane can visit [url]. | |
| 33 bool canVisit(String url); | |
| 34 } | |
| 35 | |
| 36 /// A general service object viewer. | |
| 37 class ServiceObjectPane extends Pane { | |
| 38 ServiceObjectPane(app) : super(app); | |
| 39 | |
| 40 void onInstall() { | |
| 41 if (element == null) { | |
| 42 /// Lazily create pane. | |
| 43 element = new Element.tag('service-view'); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 void visit(String url) { | |
| 48 assert(element != null); | |
| 49 assert(canVisit(url)); | |
| 50 if (url == '') { | |
| 51 // Nothing requested. | |
| 52 return; | |
| 53 } | |
| 54 /// Request url from VM and display it. | |
| 55 app.vm.get(url).then((obj) { | |
| 56 ServiceObjectViewElement pane = element; | |
| 57 pane.object = obj; | |
| 58 }); | |
| 59 } | |
| 60 | |
| 61 /// Catch all. | |
| 62 bool canVisit(String url) => true; | |
| 63 } | |
| 64 | |
| 65 /// Class tree pane. | |
| 66 class ClassTreePane extends Pane { | |
| 67 static const _urlPrefix = 'class-tree/'; | |
| 68 | |
| 69 ClassTreePane(app) : super(app); | |
| 70 | |
| 71 void onInstall() { | |
| 72 if (element == null) { | |
| 73 element = new Element.tag('class-tree'); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 void visit(String url) { | |
| 78 assert(element != null); | |
| 79 assert(canVisit(url)); | |
| 80 // ClassTree urls are 'class-tree/isolate-id', chop off prefix, leaving | |
| 81 // isolate url. | |
| 82 url = url.substring(_urlPrefix.length); | |
| 83 /// Request the isolate url. | |
| 84 app.vm.get(url).then((i) { | |
| 85 if (element != null) { | |
| 86 /// Update the pane. | |
| 87 ClassTreeElement pane = element; | |
| 88 pane.isolate = i; | |
| 89 } | |
| 90 }); | |
| 91 } | |
| 92 | |
| 93 /// Catch all. | |
| 94 bool canVisit(String url) => url.startsWith(_urlPrefix); | |
| 95 } | |
| 96 | |
| 97 class ErrorViewPane extends Pane { | |
| 98 ErrorViewPane(app) : super(app); | |
| 99 | |
| 100 void onInstall() { | |
| 101 if (element == null) { | |
| 102 /// Lazily create pane. | |
| 103 element = new Element.tag('service-view'); | |
| 104 } | |
| 105 } | |
| 106 | |
| 107 void visit(String url) { | |
| 108 assert(element != null); | |
| 109 assert(canVisit(url)); | |
| 110 (element as ServiceObjectViewElement).object = app.lastErrorOrException; | |
| 111 } | |
| 112 | |
| 113 bool canVisit(String url) => url.startsWith('error/'); | |
| 114 } | |
| 115 | |
| 116 /// The observatory application. Instances of this are created and owned | 7 /// The observatory application. Instances of this are created and owned |
| 117 /// by the observatory_application custom element. | 8 /// by the observatory_application custom element. |
| 118 class ObservatoryApplication extends Observable { | 9 class ObservatoryApplication extends Observable { |
| 119 static ObservatoryApplication app; | 10 static ObservatoryApplication app; |
| 120 final _paneRegistry = new List<Pane>(); | 11 final _paneRegistry = new List<Pane>(); |
| 121 ServiceObjectPane _serviceObjectPane; | |
| 122 Pane _currentPane; | 12 Pane _currentPane; |
| 123 @observable final LocationManager locationManager; | 13 @observable final LocationManager locationManager; |
| 124 @observable final VM vm; | 14 VM _vm; |
| 15 VM get vm => _vm; |
| 16 set vm(VM vm) { |
| 17 if (_vm == vm) { |
| 18 // Do nothing. |
| 19 return; |
| 20 } |
| 21 if (_vm != null) { |
| 22 // Disconnect from current VM. |
| 23 _vm.disconnect(); |
| 24 } |
| 25 if (vm != null) { |
| 26 Logger.root.info('Registering new VM callbacks'); |
| 27 vm.onConnect.then(_vmConnected); |
| 28 vm.onDisconnect.then(_vmDisconnected); |
| 29 vm.errors.stream.listen(_onError); |
| 30 vm.exceptions.stream.listen(_onException); |
| 31 } |
| 32 _vm = vm; |
| 33 } |
| 34 final TargetManager targets; |
| 125 @observable Isolate isolate; | 35 @observable Isolate isolate; |
| 126 @reflectable final ObservatoryApplicationElement rootElement; | 36 @reflectable final ObservatoryApplicationElement rootElement; |
| 127 | 37 |
| 128 @reflectable ServiceObject lastErrorOrException; | 38 @reflectable ServiceObject lastErrorOrException; |
| 129 | |
| 130 @observable ObservableList<ServiceEvent> notifications = | 39 @observable ObservableList<ServiceEvent> notifications = |
| 131 new ObservableList<ServiceEvent>(); | 40 new ObservableList<ServiceEvent>(); |
| 132 | 41 |
| 133 void _initOnce() { | 42 void _initOnce(bool chromium) { |
| 43 assert(app == null); |
| 134 app = this; | 44 app = this; |
| 135 vm.events.stream.listen(_handleEvent); | |
| 136 _registerPanes(); | 45 _registerPanes(); |
| 137 vm.errors.stream.listen(_onError); | |
| 138 vm.exceptions.stream.listen(_onException); | |
| 139 location = locationManager; | |
| 140 locationManager._init(this); | 46 locationManager._init(this); |
| 141 } | 47 } |
| 142 | 48 |
| 143 void removePauseEvents(Isolate isolate) { | 49 void removePauseEvents(Isolate isolate) { |
| 144 bool isPauseEvent(var event) { | 50 bool isPauseEvent(var event) { |
| 145 return (event.eventType == 'IsolateInterrupted' || | 51 return (event.eventType == 'IsolateInterrupted' || |
| 146 event.eventType == 'BreakpointReached' || | 52 event.eventType == 'BreakpointReached' || |
| 147 event.eventType == 'ExceptionThrown'); | 53 event.eventType == 'ExceptionThrown'); |
| 148 } | 54 } |
| 149 | 55 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 179 break; | 85 break; |
| 180 | 86 |
| 181 default: | 87 default: |
| 182 // Ignore unrecognized events. | 88 // Ignore unrecognized events. |
| 183 Logger.root.severe('Unrecognized event type: ${event.eventType}'); | 89 Logger.root.severe('Unrecognized event type: ${event.eventType}'); |
| 184 break; | 90 break; |
| 185 } | 91 } |
| 186 } | 92 } |
| 187 | 93 |
| 188 void _registerPanes() { | 94 void _registerPanes() { |
| 189 if (_serviceObjectPane != null) { | |
| 190 // Already done. | |
| 191 return; | |
| 192 } | |
| 193 // Register ClassTreePane. | 95 // Register ClassTreePane. |
| 194 _paneRegistry.add(new ClassTreePane(this)); | 96 _paneRegistry.add(new ClassTreePane(this)); |
| 97 _paneRegistry.add(new VMConnectPane(this)); |
| 195 _paneRegistry.add(new ErrorViewPane(this)); | 98 _paneRegistry.add(new ErrorViewPane(this)); |
| 196 // Note that ServiceObjectPane must be the last entry in the list as it is | 99 // Note that ServiceObjectPane must be the last entry in the list as it is |
| 197 // the catch all. | 100 // the catch all. |
| 198 _serviceObjectPane = new ServiceObjectPane(this); | 101 _paneRegistry.add(new ServiceObjectPane(this)); |
| 199 _paneRegistry.add(_serviceObjectPane); | |
| 200 } | 102 } |
| 201 | 103 |
| 202 void _onError(ServiceError error) { | 104 void _onError(ServiceError error) { |
| 203 lastErrorOrException = error; | 105 lastErrorOrException = error; |
| 204 _visit('error/', null); | 106 _visit('error/', null); |
| 205 } | 107 } |
| 206 | 108 |
| 207 void _onException(ServiceException exception) { | 109 void _onException(ServiceException exception) { |
| 208 lastErrorOrException = exception; | 110 lastErrorOrException = exception; |
| 209 _visit('error/', null); | 111 if (exception.kind == 'NetworkException') { |
| 112 // Got a network exception, visit the vm-connect pane. |
| 113 locationManager.go(locationManager.makeLink('/vm-connect/')); |
| 114 } else { |
| 115 _visit('error/', null); |
| 116 } |
| 210 } | 117 } |
| 211 | 118 |
| 212 void _visit(String url, String args) { | 119 void _visit(String url, String args) { |
| 213 // TODO(johnmccutchan): Pass [args] to pane. | 120 // TODO(johnmccutchan): Pass [args] to pane. |
| 214 for (var i = 0; i < _paneRegistry.length; i++) { | 121 for (var i = 0; i < _paneRegistry.length; i++) { |
| 215 var pane = _paneRegistry[i]; | 122 var pane = _paneRegistry[i]; |
| 216 if (pane.canVisit(url)) { | 123 if (pane.canVisit(url)) { |
| 217 _installPane(pane); | 124 _installPane(pane); |
| 218 pane.visit(url); | 125 pane.visit(url); |
| 219 return; | 126 return; |
| 220 } | 127 } |
| 221 } | 128 } |
| 222 throw new FallThroughError(); | 129 throw new FallThroughError(); |
| 223 } | 130 } |
| 224 | 131 |
| 225 /// Set the Observatory application pane. | 132 /// Set the Observatory application pane. |
| 226 void _installPane(Pane pane) { | 133 void _installPane(Pane pane) { |
| 227 assert(pane != null); | 134 assert(pane != null); |
| 228 print('Installing $pane'); | |
| 229 if (_currentPane == pane) { | 135 if (_currentPane == pane) { |
| 230 // Already isntalled. | 136 // Already isntalled. |
| 231 return; | 137 return; |
| 232 } | 138 } |
| 233 if (_currentPane != null) { | 139 if (_currentPane != null) { |
| 140 Logger.root.info('Uninstalling pane: $_currentPane'); |
| 234 _currentPane.onUninstall(); | 141 _currentPane.onUninstall(); |
| 142 // Clear children. |
| 143 rootElement.children.clear(); |
| 235 } | 144 } |
| 236 pane.onInstall(); | 145 Logger.root.info('Installing pane: $pane'); |
| 237 // Clear children. | 146 try { |
| 238 rootElement.children.clear(); | 147 pane.onInstall(); |
| 148 } catch (e) { |
| 149 Logger.root.severe('Failed to install pane: $e'); |
| 150 } |
| 239 // Add new pane. | 151 // Add new pane. |
| 240 rootElement.children.add(pane.element); | 152 rootElement.children.add(pane.element); |
| 241 // Remember pane. | 153 // Remember pane. |
| 242 _currentPane = pane; | 154 _currentPane = pane; |
| 243 } | 155 } |
| 244 | 156 |
| 245 ObservatoryApplication.devtools(this.rootElement) : | 157 ObservatoryApplication.devtools(this.rootElement) : |
| 246 locationManager = new HashLocationManager(), | 158 locationManager = new HashLocationManager(), |
| 247 vm = new DartiumVM() { | 159 targets = null { |
| 248 _initOnce(); | 160 vm = new PostMessageVM(); |
| 161 _initOnce(true); |
| 249 } | 162 } |
| 250 | 163 |
| 251 ObservatoryApplication(this.rootElement) : | 164 ObservatoryApplication(this.rootElement) : |
| 252 locationManager = new HashLocationManager(), | 165 locationManager = new HashLocationManager(), |
| 253 vm = new WebSocketVM() { | 166 targets = new TargetManager() { |
| 254 _initOnce(); | 167 vm = new WebSocketVM(targets.defaultTarget); |
| 168 _initOnce(false); |
| 169 } |
| 170 |
| 171 _vmConnected(VM vm) { |
| 172 if (vm is WebSocketVM) { |
| 173 targets.add(vm.target); |
| 174 } |
| 175 } |
| 176 |
| 177 _vmDisconnected(VM vm) { |
| 178 if (this.vm != vm) { |
| 179 // This disconnect event occured *after* a new VM was installed. |
| 180 return; |
| 181 } |
| 182 this.vm = null; |
| 183 locationManager.go(locationManager.makeLink('/vm-connect/')); |
| 255 } | 184 } |
| 256 } | 185 } |
| 257 | |
| 258 LocationManager location; | |
| OLD | NEW |