|  | // 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()); | 
|  | } | 
|  | } |