| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.ui.modelutil; |
| |
| import androidx.annotation.NonNull; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| /** |
| * Base class for a {@link ListObservable} containing a {@link SimpleList} of items that support |
| * sending partial change notifications. If the list item type does not support partial change |
| * notifications, use the {@link ListModel} subclass. |
| * It allows models to compose different ListObservables. |
| * @param <T> The object type that this class manages in a list. |
| * @param <P> The payload type for partial change notifications. |
| */ |
| public class ListModelBase<T, P> extends ListObservableImpl<P> implements SimpleList<T> { |
| private final List<T> mItems = new ArrayList<>(); |
| |
| /** |
| * Returns the item at the given position. |
| * @param index The position to get the item from. |
| * @return Returns the found item. |
| */ |
| @Override |
| public T get(int index) { |
| return mItems.get(index); |
| } |
| |
| @Override |
| public int size() { |
| return mItems.size(); |
| } |
| |
| @NonNull |
| @Override |
| public Iterator<T> iterator() { |
| return mItems.iterator(); |
| } |
| |
| /** |
| * Appends a given {@code item} to the last position of the held {@link List}. |
| * Notifies observers about the inserted item. |
| * @param item The item to be stored. |
| */ |
| public void add(T item) { |
| mItems.add(item); |
| notifyItemInserted(mItems.size() - 1); |
| } |
| |
| /** |
| * Inserts a given {@code item} at position {@code position} of the held {@link List}. |
| * Notifies observers about the inserted item. |
| * @param position The position of the item to be inserted. |
| * @param item The item to be inserted. |
| */ |
| public void add(int position, T item) { |
| mItems.add(position, item); |
| notifyItemInserted(position); |
| } |
| |
| /** |
| * Appends all given {@code items} to the last position of the held {@link List}. |
| * Notifies observers about the inserted items. |
| * @param items The items to be stored. |
| */ |
| public void addAll(Collection<T> items) { |
| addAll(items, mItems.size()); |
| } |
| |
| /** |
| * Adds all given {@code items} to the {@link List} at specific position. |
| * Notifies observers about the inserted items. |
| * @param items The items to be stored. |
| * @param insertionIndex Position where items should be inserted. |
| */ |
| public void addAll(Collection<? extends T> items, int insertionIndex) { |
| mItems.addAll(insertionIndex, items); |
| notifyItemRangeInserted(insertionIndex, items.size()); |
| } |
| |
| /** |
| * Appends all given {@code items} to the last position of the held {@link List}. |
| * Notifies observers about the inserted items. |
| * @param items The items to be stored. |
| */ |
| public void addAll(SimpleList<T> items) { |
| addAll(items, mItems.size()); |
| } |
| |
| /** |
| * Adds all given {@code items} to the {@link List} at specific position. |
| * Notifies observers about the inserted items. |
| * @param items The items to be stored. |
| * @param insertionIndex Position where items should be inserted. |
| */ |
| public void addAll(SimpleList<T> items, int insertionIndex) { |
| int currentIndex = insertionIndex; |
| for (T item : items) { |
| mItems.add(currentIndex++, item); |
| } |
| notifyItemRangeInserted(insertionIndex, items.size()); |
| } |
| |
| /** |
| * Removes a given item from the held {@link List}. Notifies observers about the removal. |
| * @param item The item to be removed. |
| */ |
| public void remove(T item) { |
| int position = mItems.indexOf(item); |
| removeAt(position); |
| } |
| |
| /** |
| * Removes an item by position from the held {@link List}. Notifies observers about the removal. |
| * @param position The position of the item to be removed. |
| * @return The item that has been removed. |
| */ |
| public T removeAt(int position) { |
| T item = mItems.remove(position); |
| notifyItemRemoved(position); |
| return item; |
| } |
| |
| /** |
| * Removes a range of {@code count} consecutive items from the held {@link List}, starting at |
| * {@code startPosition}. Notifies observers about the removal. |
| * @param startPosition The start position of the range of items to be removed. |
| * @param count The number of items to be removed. |
| */ |
| public void removeRange(int startPosition, int count) { |
| mItems.subList(startPosition, startPosition + count).clear(); |
| notifyItemRangeRemoved(startPosition, count); |
| } |
| |
| /** |
| * Convenience method to replace all held items with the given array of items. |
| * @param newItems The array of items that should replace all held items. |
| * @see #set(Collection) |
| */ |
| public void set(T[] newItems) { |
| set(Arrays.asList(newItems)); |
| } |
| |
| /** |
| * Replaces all held items with the given collection of items, notifying observers about the |
| * resulting insertions, deletions, changes, or combinations thereof. |
| * @param newItems The collection of items that should replace all held items. |
| */ |
| public void set(Collection<T> newItems) { |
| int oldSize = mItems.size(); |
| int newSize = newItems.size(); |
| |
| mItems.clear(); |
| mItems.addAll(newItems); |
| |
| int min = Math.min(oldSize, newSize); |
| if (min > 0) notifyItemRangeChanged(0, min); |
| |
| if (newSize > oldSize) { |
| notifyItemRangeInserted(min, newSize - oldSize); |
| } else if (newSize < oldSize) { |
| notifyItemRangeRemoved(min, oldSize - newSize); |
| } |
| } |
| |
| /** |
| * Replaces a single {@code item} at the given {@code index}. |
| * @param index The index of the item to be replaced. |
| * @param item The item to be replaced. |
| */ |
| public void update(int index, T item) { |
| mItems.set(index, item); |
| notifyItemRangeChanged(index, 1); |
| } |
| |
| /** |
| * @return The position of the given {@code item} in the held {@link List}. |
| */ |
| public int indexOf(Object item) { |
| return mItems.indexOf(item); |
| } |
| |
| /** |
| * Moves a single {@code item} from current {@code index} to new {@code index}. |
| * @param curIndex The position of the item before move. |
| * @param newIndex The position of the item after move. |
| */ |
| public void move(int curIndex, int newIndex) { |
| T item = mItems.remove(curIndex); |
| if (newIndex == mItems.size()) { |
| mItems.add(item); |
| } else { |
| mItems.add(newIndex, item); |
| } |
| notifyItemMoved(curIndex, newIndex); |
| } |
| |
| /** Clear all items from the list. */ |
| public void clear() { |
| if (size() > 0) removeRange(0, size()); |
| } |
| } |