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

Unified Diff: packages/observe/lib/src/observable_list.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « packages/observe/lib/src/observable_box.dart ('k') | packages/observe/lib/src/observable_map.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/observe/lib/src/observable_list.dart
diff --git a/packages/observe/lib/src/observable_list.dart b/packages/observe/lib/src/observable_list.dart
deleted file mode 100644
index 9d09b38d560b43844f98b40f7d2ea2ff44a28cdd..0000000000000000000000000000000000000000
--- a/packages/observe/lib/src/observable_list.dart
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library observe.src.observable_list;
-
-import 'dart:async';
-import 'dart:collection' show ListBase, UnmodifiableListView;
-import 'package:observe/observe.dart';
-import 'list_diff.dart' show projectListSplices, calcSplices;
-
-/// Represents an observable list of model values. If any items are added,
-/// removed, or replaced, then observers that are listening to [changes]
-/// will be notified.
-class ObservableList<E> extends ListBase<E> with ChangeNotifier {
- List<ListChangeRecord> _listRecords;
-
- StreamController _listChanges;
-
- /// The inner [List<E>] with the actual storage.
- final List<E> _list;
-
- /// Creates an observable list of the given [length].
- ///
- /// If no [length] argument is supplied an extendable list of
- /// length 0 is created.
- ///
- /// If a [length] argument is supplied, a fixed size list of that
- /// length is created.
- ObservableList([int length])
- : _list = length != null ? new List<E>(length) : <E>[];
-
- /// Creates an observable list with the elements of [other]. The order in
- /// the list will be the order provided by the iterator of [other].
- factory ObservableList.from(Iterable<E> other) =>
- new ObservableList<E>()..addAll(other);
-
- /// The stream of summarized list changes, delivered asynchronously.
- ///
- /// Each list change record contains information about an individual mutation.
- /// The records are projected so they can be applied sequentially. For
- /// example, this set of mutations:
- ///
- /// var model = new ObservableList.from(['a', 'b']);
- /// model.listChanges.listen((records) => records.forEach(print));
- /// model.removeAt(1);
- /// model.insertAll(0, ['c', 'd', 'e']);
- /// model.removeRange(1, 3);
- /// model.insert(1, 'f');
- ///
- /// The change records will be summarized so they can be "played back", using
- /// the final list positions to figure out which item was added:
- ///
- /// #<ListChangeRecord index: 0, removed: [], addedCount: 2>
- /// #<ListChangeRecord index: 3, removed: [b], addedCount: 0>
- ///
- /// [deliverChanges] can be called to force synchronous delivery.
- Stream<List<ListChangeRecord>> get listChanges {
- if (_listChanges == null) {
- // TODO(jmesserly): split observed/unobserved notions?
- _listChanges = new StreamController.broadcast(sync: true,
- onCancel: () { _listChanges = null; });
- }
- return _listChanges.stream;
- }
-
- bool get hasListObservers =>
- _listChanges != null && _listChanges.hasListener;
-
- @reflectable int get length => _list.length;
-
- @reflectable set length(int value) {
- int len = _list.length;
- if (len == value) return;
-
- // Produce notifications if needed
- _notifyChangeLength(len, value);
- if (hasListObservers) {
- if (value < len) {
- _recordChange(new ListChangeRecord(this, value,
- removed: _list.getRange(value, len).toList()));
- } else {
- _recordChange(new ListChangeRecord(this, len, addedCount: value - len));
- }
- }
-
- _list.length = value;
- }
-
- @reflectable E operator [](int index) => _list[index];
-
- @reflectable void operator []=(int index, E value) {
- var oldValue = _list[index];
- if (hasListObservers && oldValue != value) {
- _recordChange(new ListChangeRecord(this, index, addedCount: 1,
- removed: [oldValue]));
- }
- _list[index] = value;
- }
-
- // Forwarders so we can reflect on the properties.
- @reflectable bool get isEmpty => super.isEmpty;
- @reflectable bool get isNotEmpty => super.isNotEmpty;
-
- // TODO(jmesserly): should we support first/last/single? They're kind of
- // dangerous to use in a path because they throw exceptions. Also we'd need
- // to produce property change notifications which seems to conflict with our
- // existing list notifications.
-
- // The following methods are here so that we can provide nice change events.
-
- void setAll(int index, Iterable<E> iterable) {
- if (iterable is! List && iterable is! Set) {
- iterable = iterable.toList();
- }
- var len = iterable.length;
- if (hasListObservers && len > 0) {
- _recordChange(new ListChangeRecord(this, index, addedCount: len,
- removed: _list.getRange(index, len).toList()));
- }
- _list.setAll(index, iterable);
- }
-
- void add(E value) {
- int len = _list.length;
- _notifyChangeLength(len, len + 1);
- if (hasListObservers) {
- _recordChange(new ListChangeRecord(this, len, addedCount: 1));
- }
-
- _list.add(value);
- }
-
- void addAll(Iterable<E> iterable) {
- int len = _list.length;
- _list.addAll(iterable);
-
- _notifyChangeLength(len, _list.length);
-
- int added = _list.length - len;
- if (hasListObservers && added > 0) {
- _recordChange(new ListChangeRecord(this, len, addedCount: added));
- }
- }
-
- bool remove(Object element) {
- for (int i = 0; i < this.length; i++) {
- if (this[i] == element) {
- removeRange(i, i + 1);
- return true;
- }
- }
- return false;
- }
-
- void removeRange(int start, int end) {
- _rangeCheck(start, end);
- int rangeLength = end - start;
- int len = _list.length;
-
- _notifyChangeLength(len, len - rangeLength);
- if (hasListObservers && rangeLength > 0) {
- _recordChange(new ListChangeRecord(this, start,
- removed: _list.getRange(start, end).toList()));
- }
-
- _list.removeRange(start, end);
- }
-
- void insertAll(int index, Iterable<E> iterable) {
- if (index < 0 || index > length) {
- throw new RangeError.range(index, 0, length);
- }
- // TODO(floitsch): we can probably detect more cases.
- if (iterable is! List && iterable is! Set) {
- iterable = iterable.toList();
- }
- int insertionLength = iterable.length;
- // There might be errors after the length change, in which case the list
- // will end up being modified but the operation not complete. Unless we
- // always go through a "toList" we can't really avoid that.
- int len = _list.length;
- _list.length += insertionLength;
-
- _list.setRange(index + insertionLength, this.length, this, index);
- _list.setAll(index, iterable);
-
- _notifyChangeLength(len, _list.length);
-
- if (hasListObservers && insertionLength > 0) {
- _recordChange(new ListChangeRecord(this, index,
- addedCount: insertionLength));
- }
- }
-
- void insert(int index, E element) {
- if (index < 0 || index > length) {
- throw new RangeError.range(index, 0, length);
- }
- if (index == length) {
- add(element);
- return;
- }
- // We are modifying the length just below the is-check. Without the check
- // Array.copy could throw an exception, leaving the list in a bad state
- // (with a length that has been increased, but without a new element).
- if (index is! int) throw new ArgumentError(index);
- _list.length++;
- _list.setRange(index + 1, length, this, index);
-
- _notifyChangeLength(_list.length - 1, _list.length);
- if (hasListObservers) {
- _recordChange(new ListChangeRecord(this, index, addedCount: 1));
- }
- _list[index] = element;
- }
-
-
- E removeAt(int index) {
- E result = this[index];
- removeRange(index, index + 1);
- return result;
- }
-
- void _rangeCheck(int start, int end) {
- if (start < 0 || start > this.length) {
- throw new RangeError.range(start, 0, this.length);
- }
- if (end < start || end > this.length) {
- throw new RangeError.range(end, start, this.length);
- }
- }
-
- void _recordChange(ListChangeRecord record) {
- if (!hasListObservers) return;
-
- if (_listRecords == null) {
- _listRecords = [];
- scheduleMicrotask(deliverListChanges);
- }
- _listRecords.add(record);
- }
-
- void _notifyChangeLength(int oldValue, int newValue) {
- notifyPropertyChange(#length, oldValue, newValue);
- notifyPropertyChange(#isEmpty, oldValue == 0, newValue == 0);
- notifyPropertyChange(#isNotEmpty, oldValue != 0, newValue != 0);
- }
-
- /// Deprecated. Name had a typo, use [discardListChanges] instead.
- @deprecated
- void discardListChages() => discardListChanges();
-
- void discardListChanges() {
- // Leave _listRecords set so we don't schedule another delivery.
- if (_listRecords != null) _listRecords = [];
- }
-
- bool deliverListChanges() {
- if (_listRecords == null) return false;
- var records = projectListSplices(this, _listRecords);
- _listRecords = null;
-
- if (hasListObservers && !records.isEmpty) {
- _listChanges.add(new UnmodifiableListView<ListChangeRecord>(records));
- return true;
- }
- return false;
- }
-
- /// Calculates the changes to the list, if lacking individual splice mutation
- /// information.
- ///
- /// This is not needed for change records produced by [ObservableList] itself,
- /// but it can be used if the list instance was replaced by another list.
- ///
- /// The minimal set of splices can be synthesized given the previous state and
- /// final state of a list. The basic approach is to calculate the edit
- /// distance matrix and choose the shortest path through it.
- ///
- /// Complexity is `O(l * p)` where `l` is the length of the current list and
- /// `p` is the length of the old list.
- static List<ListChangeRecord> calculateChangeRecords(
- List<Object> oldValue, List<Object> newValue) =>
- calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length);
-
- /// Updates the [previous] list using the change [records]. For added items,
- /// the [current] list is used to find the current value.
- static void applyChangeRecords(List<Object> previous, List<Object> current,
- List<ListChangeRecord> changeRecords) {
-
- if (identical(previous, current)) {
- throw new ArgumentError("can't use same list for previous and current");
- }
-
- for (var change in changeRecords) {
- int addEnd = change.index + change.addedCount;
- int removeEnd = change.index + change.removed.length;
-
- var addedItems = current.getRange(change.index, addEnd);
- previous.replaceRange(change.index, removeEnd, addedItems);
- }
- }
-}
« no previous file with comments | « packages/observe/lib/src/observable_box.dart ('k') | packages/observe/lib/src/observable_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698