Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(219)

Side by Side Diff: pkg/observe/lib/src/change_notifier.dart

Issue 20631002: [pkg:observe] Add support for explicit change notification, even on dirty-checked objects (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: revert pubspec Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/observe/lib/src/observable.dart » ('j') | pkg/observe/lib/src/observable.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 observe; 5 part of observe;
6 6
7 /** 7 /**
8 * Interface representing an [Observable] object that performs its own change 8 * Base class implementing [Observable] object that performs its own change
9 * notifications, and does not need to be considered by [Observable.dirtyCheck]. 9 * notifications, and does not need to be considered by [Observable.dirtyCheck].
10 */
11 abstract class ChangeNotifier extends Observable {
12 /**
13 * Notify observers of a change.
14 *
15 * For most objects [ChangeNotifierMixin.notifyPropertyChange] is more
16 * convenient, but collections sometimes deliver other types of changes such
17 * as a [ListChangeRecord].
18 */
19 void notifyChange(ChangeRecord record);
20 }
21
22 /**
23 * Base class implementing [ChangeNotifier].
24 * 10 *
25 * When a field, property, or indexable item is changed, a derived class should 11 * When a field, property, or indexable item is changed, a derived class should
26 * call [notifyPropertyChange]. See that method for an example. 12 * call [notifyPropertyChange]. See that method for an example.
27 */ 13 */
28 typedef ChangeNotifierBase = Object with ChangeNotifierMixin; 14 typedef ChangeNotifierBase = Object with ChangeNotifierMixin;
29 15
30 /** 16 /**
31 * Mixin for implementing [ChangeNotifier] objects. 17 * Mixin implementing [Observable] object that performs its own change
18 * notifications, and does not need to be considered by [Observable.dirtyCheck].
32 * 19 *
33 * When a field, property, or indexable item is changed, a derived class should 20 * When a field, property, or indexable item is changed, a derived class should
34 * call [notifyPropertyChange]. See that method for an example. 21 * call [notifyPropertyChange]. See that method for an example.
35 */ 22 */
36 abstract class ChangeNotifierMixin implements ChangeNotifier { 23 abstract class ChangeNotifierMixin implements Observable {
37 StreamController _changes; 24 StreamController _changes;
38 List<ChangeRecord> _records; 25 List<ChangeRecord> _records;
39 26
40 Stream<List<ChangeRecord>> get changes { 27 Stream<List<ChangeRecord>> get changes {
41 if (_changes == null) { 28 if (_changes == null) {
42 _changes = new StreamController.broadcast(sync: true, 29 _changes = new StreamController.broadcast(sync: true,
43 onListen: _observed, onCancel: _unobserved); 30 onListen: _observed, onCancel: _unobserved);
44 } 31 }
45 return _changes.stream; 32 return _changes.stream;
46 } 33 }
47 34
48 // TODO(jmesserly): should these be public? They're useful lifecycle methods 35 // TODO(jmesserly): should these be public? They're useful lifecycle methods
49 // for subclasses. Ideally they'd be protected. 36 // for subclasses. Ideally they'd be protected.
50 /** 37 /**
51 * Override this method to be called when the [changes] are first observed. 38 * Override this method to be called when the [changes] are first observed.
52 */ 39 */
53 void _observed() {} 40 void _observed() {}
54 41
55 /** 42 /**
56 * Override this method to be called when the [changes] are no longer being 43 * Override this method to be called when the [changes] are no longer being
57 * observed. 44 * observed.
58 */ 45 */
59 void _unobserved() {} 46 void _unobserved() {}
60 47
61 bool deliverChanges() { 48 bool deliverChanges() {
62 var records = _records; 49 var records = _records;
63 _records = null; 50 _records = null;
64 if (hasObservers && records != null) { 51 if (hasObservers && records != null) {
65 // TODO(jmesserly): make "records" immutable 52 _changes.add(new UnmodifiableListView<ChangeRecord>(records));
66 _changes.add(records);
67 return true; 53 return true;
68 } 54 }
69 return false; 55 return false;
70 } 56 }
71 57
72 /** 58 /**
73 * True if this object has any observers, and should call 59 * True if this object has any observers, and should call
74 * [notifyPropertyChange] for changes. 60 * [notifyPropertyChange] for changes.
75 */ 61 */
76 bool get hasObservers => _changes != null && _changes.hasListener; 62 bool get hasObservers => _changes != null && _changes.hasListener;
77 63
78 /** 64 /**
79 * Notify that the field [name] of this object has been changed. 65 * Notify that the field [name] of this object has been changed.
80 * 66 *
81 * The [oldValue] and [newValue] are also recorded. If the two values are 67 * The [oldValue] and [newValue] are also recorded. If the two values are
82 * identical, no change will be recorded. 68 * identical, no change will be recorded.
83 * 69 *
84 * For convenience this returns [newValue]. This makes it easy to use in a 70 * For convenience this returns [newValue]. This makes it easy to use in a
85 * setter: 71 * setter:
86 * 72 *
87 * var _myField; 73 * var _myField;
88 * get myField => _myField; 74 * get myField => _myField;
89 * set myField(value) { 75 * set myField(value) {
90 * _myField = notifyPropertyChange( 76 * _myField = notifyPropertyChange(
91 * const Symbol('myField'), _myField, value); 77 * const Symbol('myField'), _myField, value);
92 * } 78 * }
93 */ 79 */
94 // TODO(jmesserly): should this be == instead of identical, to prevent 80 notifyPropertyChange(Symbol field, Object oldValue, Object newValue)
95 // spurious loops? 81 => _notifyPropertyChange(this, field, oldValue, newValue);
96 notifyPropertyChange(Symbol field, Object oldValue, Object newValue) {
97 if (hasObservers && !identical(oldValue, newValue)) {
98 notifyChange(new PropertyChangeRecord(field));
99 }
100 return newValue;
101 }
102 82
103 void notifyChange(ChangeRecord record) { 83 void notifyChange(ChangeRecord record) {
104 if (!hasObservers) return; 84 if (!hasObservers) return;
105 85
106 if (_records == null) { 86 if (_records == null) {
107 _records = []; 87 _records = [];
108 runAsync(deliverChanges); 88 runAsync(deliverChanges);
109 } 89 }
110 _records.add(record); 90 _records.add(record);
111 } 91 }
112 } 92 }
OLDNEW
« no previous file with comments | « no previous file | pkg/observe/lib/src/observable.dart » ('j') | pkg/observe/lib/src/observable.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698