private static IChangeSet <T> Virtualise(List <T> all, ChangeAwareList <T> virtualised, IVirtualRequest request, IChangeSet <T> changeset = null) { if (changeset != null) { all.Clone(changeset); } var previous = virtualised; var current = all.Skip(request.StartIndex) .Take(request.Size) .ToList(); var adds = current.Except(previous); var removes = previous.Except(current); virtualised.RemoveMany(removes); adds.ForEach(t => { var index = current.IndexOf(t); virtualised.Insert(index, t); }); var moves = changeset.EmptyIfNull() .Where(change => change.Reason == ListChangeReason.Moved && change.MovedWithinRange(request.StartIndex, request.StartIndex + request.Size)); foreach (var change in moves) { //check whether an item has moved within the same page var currentIndex = change.Item.CurrentIndex - request.StartIndex; var previousIndex = change.Item.PreviousIndex - request.StartIndex; virtualised.Move(previousIndex, currentIndex); } //find replaces [Is this ever the case that it can be reached] for (var i = 0; i < current.Count; i++) { var currentItem = current[i]; var previousItem = previous[i]; if (ReferenceEquals(currentItem, previousItem)) { continue; } var index = virtualised.IndexOf(currentItem); virtualised.Move(i, index); } return(virtualised.CaptureChanges()); }
private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } foreach (var item in changes) { switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count) { transformed.Add(_containerFactory(change.Current, Optional <TDestination> .None, transformed.Count)); } else { var converted = _containerFactory(change.Current, Optional <TDestination> .None, change.CurrentIndex); transformed.Insert(change.CurrentIndex, converted); } break; } case ListChangeReason.AddRange: { var startIndex = item.Range.Index < 0 ? transformed.Count : item.Range.Index; transformed.AddOrInsertRange(item.Range .Select((t, idx) => _containerFactory(t, Optional <TDestination> .None, idx + startIndex)), item.Range.Index); break; } case ListChangeReason.Refresh: { if (_transformOnRefresh) { var change = item.Item; Optional <TDestination> previous = transformed[change.CurrentIndex].Destination; var refreshed = _containerFactory(change.Current, previous, change.CurrentIndex); transformed[change.CurrentIndex] = refreshed; } else { transformed.RefreshAt(item.Item.CurrentIndex); } break; } case ListChangeReason.Replace: { var change = item.Item; Optional <TDestination> previous = transformed[change.PreviousIndex].Destination; if (change.CurrentIndex == change.PreviousIndex) { transformed[change.CurrentIndex] = _containerFactory(change.Current, previous, change.CurrentIndex); } else { transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, _containerFactory(change.Current, Optional <TDestination> .None, change.CurrentIndex)); } break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { transformed.RemoveAt(change.CurrentIndex); } else { var toRemove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, change.Current)); if (toRemove != null) { transformed.Remove(toRemove); } } break; } case ListChangeReason.RemoveRange: { if (item.Range.Index >= 0) { transformed.RemoveRange(item.Range.Index, item.Range.Count); } else { var toRemove = transformed.Where(t => item.Range.Any(current => ReferenceEquals(t.Source, current))); transformed.RemoveMany(toRemove); } break; } case ListChangeReason.Clear: { //i.e. need to store transformed reference so we can correctly clear var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed); transformed.ClearOrRemoveMany(toClear); break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } transformed.Move(change.PreviousIndex, change.CurrentIndex); break; } } } }
private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes) { if (changes == null) { throw new ArgumentNullException(nameof(changes)); } transformed.EnsureCapacityFor(changes); foreach (var item in changes) { switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count) { transformed.Add(_containerFactory(change.Current)); } else { transformed.Insert(change.CurrentIndex, _containerFactory(change.Current)); } break; } case ListChangeReason.AddRange: { transformed.AddOrInsertRange(item.Range.Select(_containerFactory), item.Range.Index); break; } case ListChangeReason.Replace: { var change = item.Item; if (change.CurrentIndex == change.PreviousIndex) { transformed[change.CurrentIndex] = _containerFactory(change.Current); } else { transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, _containerFactory(change.Current)); } break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { transformed.RemoveAt(item.Item.CurrentIndex); } else { var toremove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t)); if (toremove != null) { transformed.Remove(toremove); } } break; } case ListChangeReason.RemoveRange: { if (item.Range.Index >= 0) { transformed.RemoveRange(item.Range.Index, item.Range.Count); } else { var toremove = transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray(); transformed.RemoveMany(toremove); } break; } case ListChangeReason.Clear: { //i.e. need to store transformed reference so we can correctly clear var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed); transformed.ClearOrRemoveMany(toClear); break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } var collection = transformed as IExtendedList <TransformedItemContainer>; if (collection != null) { collection.Move(change.PreviousIndex, change.CurrentIndex); } else { var current = transformed[change.PreviousIndex]; transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, current); } break; } } } }
private void Insert(ChangeAwareList <T> target, T item) { var index = GetInsertPosition(target, item); target.Insert(index, item); }
private PageChangeSet <T> Page(List <T> all, ChangeAwareList <T> paged, IPageRequest request, IChangeSet <T> changeset = null) { if (changeset != null) { all.Clone(changeset); } var previous = paged; int pages = CalculatePages(all, request); int page = request.Page > pages ? pages : request.Page; int skip = request.Size * (page - 1); var current = all.Skip(skip) .Take(request.Size) .ToList(); var adds = current.Except(previous); var removes = previous.Except(current); paged.RemoveMany(removes); adds.ForEach(t => { var index = current.IndexOf(t); paged.Insert(index, t); }); var startIndex = skip; var moves = changeset.EmptyIfNull() .Where(change => change.Reason == ListChangeReason.Moved && change.MovedWithinRange(startIndex, startIndex + request.Size)); foreach (var change in moves) { //check whether an item has moved within the same page var currentIndex = change.Item.CurrentIndex - startIndex; var previousIndex = change.Item.PreviousIndex - startIndex; paged.Move(previousIndex, currentIndex); } //find replaces [Is this ever the case that it can be reached] for (int i = 0; i < current.Count; i++) { var currentItem = current[i]; var previousItem = previous[i]; if (ReferenceEquals(currentItem, previousItem)) { continue; } var index = paged.IndexOf(currentItem); paged.Move(i, index); } var changed = paged.CaptureChanges(); return(new PageChangeSet <T>(changed, new PageResponse(paged.Count, page, all.Count, pages))); }
private async Task Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes) { if (changes is null) { throw new ArgumentNullException(nameof(changes)); } foreach (var item in changes) { switch (item.Reason) { case ListChangeReason.Add: { var change = item.Item; if (change.CurrentIndex < 0 | change.CurrentIndex >= transformed.Count) { var container = await _containerFactory(item.Item.Current).ConfigureAwait(false); transformed.Add(container); } else { var container = await _containerFactory(item.Item.Current).ConfigureAwait(false); transformed.Insert(change.CurrentIndex, container); } break; } case ListChangeReason.AddRange: { var tasks = item.Range.Select(_containerFactory); var containers = await Task.WhenAll(tasks).ConfigureAwait(false); transformed.AddOrInsertRange(containers, item.Range.Index); break; } case ListChangeReason.Replace: { var change = item.Item; var container = await _containerFactory(item.Item.Current).ConfigureAwait(false); if (change.CurrentIndex == change.PreviousIndex) { transformed[change.CurrentIndex] = container; } else { transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, container); } break; } case ListChangeReason.Remove: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (hasIndex) { transformed.RemoveAt(item.Item.CurrentIndex); } else { var toRemove = transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t)); if (toRemove is not null) { transformed.Remove(toRemove); } } break; } case ListChangeReason.RemoveRange: { if (item.Range.Index >= 0) { transformed.RemoveRange(item.Range.Index, item.Range.Count); } else { var toRemove = transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray(); transformed.RemoveMany(toRemove); } break; } case ListChangeReason.Clear: { // i.e. need to store transformed reference so we can correctly clear var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, transformed); transformed.ClearOrRemoveMany(toClear); break; } case ListChangeReason.Moved: { var change = item.Item; bool hasIndex = change.CurrentIndex >= 0; if (!hasIndex) { throw new UnspecifiedIndexException("Cannot move as an index was not specified"); } if (transformed is IExtendedList <TransformedItemContainer> collection) { collection.Move(change.PreviousIndex, change.CurrentIndex); } else { var current = transformed[change.PreviousIndex]; transformed.RemoveAt(change.PreviousIndex); transformed.Insert(change.CurrentIndex, current); } break; } } } }