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

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

Issue 14732003: Implement Model-Driven-Views spec for Dart (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: comment tweaks Created 7 years, 7 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 | « pkg/observe/lib/src/observable_box.dart ('k') | pkg/observe/lib/src/observable_map.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of observe;
6
7 /**
8 * Represents an observable list of model values. If any items are added,
9 * removed, or replaced, then observers that are listening to [changes]
10 * will be notified.
11 */
12 // TODO(jmesserly): remove implements List<E> once we can extend ListBase<E>
13 class ObservableList<E> extends _ListBaseWorkaround with ObservableMixin
14 implements List<E> {
15
16 static const _LENGTH = const Symbol('length');
17
18 /** The inner [List<E>] with the actual storage. */
19 final List<E> _list;
20
21 /**
22 * Creates an observable list of the given [length].
23 *
24 * If no [length] argument is supplied an extendable list of
25 * length 0 is created.
26 *
27 * If a [length] argument is supplied, a fixed size list of that
28 * length is created.
29 */
30 ObservableList([int length])
31 : _list = length != null ? new List<E>(length) : <E>[];
32
33 /**
34 * Creates an observable list with the elements of [other]. The order in
35 * the list will be the order provided by the iterator of [other].
36 */
37 factory ObservableList.from(Iterable<E> other) =>
38 new ObservableList<E>()..addAll(other);
39
40 // TODO(jmesserly): remove once we have mirrors
41 getValueWorkaround(key) => identical(key, _LENGTH) ? length : null;
42
43 setValueWorkaround(key, value) {
44 if (identical(key, _LENGTH)) length = value;
45 }
46
47 int get length => _list.length;
48
49 set length(int value) {
50 int len = _list.length;
51 if (len == value) return;
52
53 // Produce notifications if needed
54 if (hasObservers) {
55 if (value < len) {
56 // Remove items, then adjust length. Note the reverse order.
57 notifyChange(new ListChangeRecord(value, removedCount: len - value));
58 notifyField(_LENGTH, len, value);
59 } else {
60 // Adjust length then add items
61 notifyField(_LENGTH, len, value);
62 notifyChange(new ListChangeRecord(len, addedCount: value - len));
63 }
64 }
65
66 _list.length = value;
67 }
68
69 E operator [](int index) => _list[index];
70
71 void operator []=(int index, E value) {
72 var oldValue = _list[index];
73 if (hasObservers) {
74 notifyChange(new ListChangeRecord(index, addedCount: 1, removedCount: 1));
75 }
76 _list[index] = value;
77 }
78
79 // The following methods are here so that we can provide nice change events.
80
81 void setAll(int index, Iterable<E> iterable) {
82 if (iterable is! List && iterable is! Set) {
83 iterable = iterable.toList();
84 }
85 var len = iterable.length;
86 _list.setAll(index, iterable);
87 if (hasObservers) {
88 notifyChange(
89 new ListChangeRecord(index, addedCount: len, removedCount: len));
90 }
91 }
92
93 void add(E value) {
94 int len = _list.length;
95 if (hasObservers) {
96 notifyField(_LENGTH, len, len + 1);
97 notifyChange(new ListChangeRecord(len, addedCount: 1));
98 }
99
100 _list.add(value);
101 }
102
103 void addAll(Iterable<E> iterable) {
104 int len = _list.length;
105 _list.addAll(iterable);
106 noitifyChange(new ListChangeRecord(len, addedCount: _list.length - len));
107 notifyField(_LENGTH, len, _list.length);
108 }
109
110 bool remove(Object element) {
111 for (int i = 0; i < this.length; i++) {
112 if (this[i] == element) {
113 removeRange(i, 1);
114 return true;
115 }
116 }
117 return false;
118 }
119
120 void removeRange(int start, int end) {
121 _rangeCheck(start, end);
122 int length = end - start;
123 _list.setRange(start, this.length - length, this, end);
124
125 int len = _list.length;
126 _list.length -= length;
127 if (hasObservers) {
128 notifyChange(new ListChangeRecord(len, removedCount: length));
129 notifyField(_LENGTH, len, _list.length);
130 }
131 }
132
133 void insertAll(int index, Iterable<E> iterable) {
floitsch 2013/05/07 14:46:48 Why is this not just: var oldLength = _list.length
134 if (index < 0 || index > length) {
135 throw new RangeError.range(index, 0, length);
136 }
137 // TODO(floitsch): we can probably detect more cases.
138 if (iterable is! List && iterable is! Set) {
139 iterable = iterable.toList();
140 }
141 int insertionLength = iterable.length;
142 // There might be errors after the length change, in which case the list
143 // will end up being modified but the operation not complete. Unless we
144 // always go through a "toList" we can't really avoid that.
145 int len = _list.length;
146 _list.length += insertionLength;
147
148 _list.setRange(index + insertionLength, this.length, this, index);
149
150 if (hasObservers) {
151 notifyField(_LENGTH, len, _list.length);
152 notifyChange(new ListChangeRecord(index, addedCount: insertionLength);
153 } else {
154 setAll(index, iterable);
155 }
156 }
157
158 void insert(int index, E element) {
159 if (index < 0 || index > length) {
160 throw new RangeError.range(index, 0, length);
161 }
162 if (index == this.length) {
163 add(element);
164 return;
165 }
166 // We are modifying the length just below the is-check. Without the check
167 // Array.copy could throw an exception, leaving the list in a bad state
168 // (with a length that has been increased, but without a new element).
169 if (index is! int) throw new ArgumentError(index);
170 this.length++;
171 _list.setRange(index + 1, this.length, this, index);
172 notifyChange(new ListChangeRecord(index, addedCount: 1);
173 _list[index] = element;
174 }
175
176
177 E removeAt(int index) {
178 E result = this[index];
179 removeRange(index, index + 1);
180 return result;
181 }
182
183 void _rangeCheck(int start, int end) {
184 if (start < 0 || start > this.length) {
185 throw new RangeError.range(start, 0, this.length);
186 }
187 if (end < start || end > this.length) {
188 throw new RangeError.range(end, start, this.length);
189 }
190 }
191 }
192
193
194 // TODO(jmesserly): bogus type to workaround spurious VM bug with generic base
195 // class and mixins.
196 abstract class _ListBaseWorkaround extends ListBase<dynamic> {}
OLDNEW
« no previous file with comments | « pkg/observe/lib/src/observable_box.dart ('k') | pkg/observe/lib/src/observable_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698