| 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 observe.src.path_observer; | 5 library observe.src.path_observer; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 import 'dart:math' show min; | 9 import 'dart:math' show min; |
| 10 | 10 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 /// See [open] and [value]. | 34 /// See [open] and [value]. |
| 35 PathObserver(Object object, [path]) | 35 PathObserver(Object object, [path]) |
| 36 : _object = object, | 36 : _object = object, |
| 37 _path = path is PropertyPath ? path : new PropertyPath(path); | 37 _path = path is PropertyPath ? path : new PropertyPath(path); |
| 38 | 38 |
| 39 bool get _isClosed => _path == null; | 39 bool get _isClosed => _path == null; |
| 40 | 40 |
| 41 /// Sets the value at this path. | 41 /// Sets the value at this path. |
| 42 void set value(Object newValue) { | 42 void set value(Object newValue) { |
| 43 if (_path != null) _path.setValueFrom(_object, newValue); | 43 if (_path != null) _path.setValueFrom(_object, newValue); |
| 44 _discardChanges(); |
| 44 } | 45 } |
| 45 | 46 |
| 46 int get _reportArgumentCount => 2; | 47 int get _reportArgumentCount => 2; |
| 47 | 48 |
| 48 /// Initiates observation and returns the initial value. | 49 /// Initiates observation and returns the initial value. |
| 49 /// The callback will be passed the updated [value], and may optionally be | 50 /// The callback will be passed the updated [value], and may optionally be |
| 50 /// declared to take a second argument, which will contain the previous value. | 51 /// declared to take a second argument, which will contain the previous value. |
| 51 open(callback) => super.open(callback); | 52 open(callback) => super.open(callback); |
| 52 | 53 |
| 53 void _connect() { | 54 void _connect() { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 424 | 425 |
| 425 if (path is! PropertyPath) path = new PropertyPath(path); | 426 if (path is! PropertyPath) path = new PropertyPath(path); |
| 426 _observed..add(object)..add(path); | 427 _observed..add(object)..add(path); |
| 427 } | 428 } |
| 428 | 429 |
| 429 void addObserver(Bindable observer) { | 430 void addObserver(Bindable observer) { |
| 430 if (_isOpen || _isClosed) { | 431 if (_isOpen || _isClosed) { |
| 431 throw new StateError('Cannot add observers once started.'); | 432 throw new StateError('Cannot add observers once started.'); |
| 432 } | 433 } |
| 433 | 434 |
| 434 observer.open(_deliver); | 435 observer.open((_) => deliver()); |
| 435 _observed..add(_observerSentinel)..add(observer); | 436 _observed..add(_observerSentinel)..add(observer); |
| 436 } | 437 } |
| 437 | 438 |
| 438 void _iterateObjects(void observe(obj)) { | 439 void _iterateObjects(void observe(obj)) { |
| 439 for (var i = 0; i < _observed.length; i += 2) { | 440 for (var i = 0; i < _observed.length; i += 2) { |
| 440 var object = _observed[i]; | 441 var object = _observed[i]; |
| 441 if (!identical(object, _observerSentinel)) { | 442 if (!identical(object, _observerSentinel)) { |
| 442 (_observed[i + 1] as PropertyPath)._iterateObjects(object, observe); | 443 (_observed[i + 1] as PropertyPath)._iterateObjects(object, observe); |
| 443 } | 444 } |
| 444 } | 445 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 'fewer arguments'); | 526 'fewer arguments'); |
| 526 } | 527 } |
| 527 | 528 |
| 528 _notifyCallback = callback; | 529 _notifyCallback = callback; |
| 529 _notifyArgumentCount = min(_reportArgumentCount, smoke.maxArgs(callback)); | 530 _notifyArgumentCount = min(_reportArgumentCount, smoke.maxArgs(callback)); |
| 530 | 531 |
| 531 _connect(); | 532 _connect(); |
| 532 return _value; | 533 return _value; |
| 533 } | 534 } |
| 534 | 535 |
| 535 get value { | 536 get value => _discardChanges(); |
| 536 _check(skipChanges: true); | |
| 537 return _value; | |
| 538 } | |
| 539 | 537 |
| 540 void close() { | 538 void close() { |
| 541 if (!_isOpen) return; | 539 if (!_isOpen) return; |
| 542 | 540 |
| 543 _disconnect(); | 541 _disconnect(); |
| 544 _value = null; | 542 _value = null; |
| 545 _notifyCallback = null; | 543 _notifyCallback = null; |
| 546 } | 544 } |
| 547 | 545 |
| 548 void _deliver(_) { | 546 _discardChanges() { |
| 549 if (_isOpen) _dirtyCheck(); | 547 _check(skipChanges: true); |
| 548 return _value; |
| 550 } | 549 } |
| 551 | 550 |
| 551 bool deliver() => _isOpen ? _dirtyCheck() : false; |
| 552 |
| 552 bool _dirtyCheck() { | 553 bool _dirtyCheck() { |
| 553 var cycles = 0; | 554 var cycles = 0; |
| 554 while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) { | 555 while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) { |
| 555 cycles++; | 556 cycles++; |
| 556 } | 557 } |
| 557 return cycles > 0; | 558 return cycles > 0; |
| 558 } | 559 } |
| 559 | 560 |
| 560 void _report(newValue, oldValue, [extraArg]) { | 561 void _report(newValue, oldValue, [extraArg]) { |
| 561 try { | 562 try { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 for (var observer in _observers.values.toList(growable: false)) { | 671 for (var observer in _observers.values.toList(growable: false)) { |
| 671 if (observer._isOpen) observer._check(); | 672 if (observer._isOpen) observer._check(); |
| 672 } | 673 } |
| 673 | 674 |
| 674 _resetNeeded = true; | 675 _resetNeeded = true; |
| 675 scheduleMicrotask(reset); | 676 scheduleMicrotask(reset); |
| 676 } | 677 } |
| 677 } | 678 } |
| 678 | 679 |
| 679 const int _MAX_DIRTY_CHECK_CYCLES = 1000; | 680 const int _MAX_DIRTY_CHECK_CYCLES = 1000; |
| OLD | NEW |