/*
* Copyright 2014 Niek Haarman
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nhaarman.listviewanimations;
import android.database.DataSetObserver;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.SectionIndexer;
import com.nhaarman.listviewanimations.util.AbsListViewWrapper;
import com.nhaarman.listviewanimations.util.Insertable;
import com.nhaarman.listviewanimations.util.ListViewWrapper;
import com.nhaarman.listviewanimations.util.ListViewWrapperSetter;
import com.nhaarman.listviewanimations.util.Swappable;
import com.pan.simplepicture.annotations.NonNull;
import com.pan.simplepicture.annotations.Nullable;
/**
* A decorator class that enables decoration of an instance of the
* {@link BaseAdapter} class.
* <p/>
* Classes extending this class can override methods and provide extra
* functionality before or after calling the super method.
*/
public abstract class BaseAdapterDecorator extends BaseAdapter implements
SectionIndexer, Swappable, Insertable, ListViewWrapperSetter {
/**
* The {@link android.widget.BaseAdapter} this {@code BaseAdapterDecorator}
* decorates.
*/
@NonNull
private final BaseAdapter mDecoratedBaseAdapter;
/**
* The {@link com.nhaarman.listviewanimations.util.ListViewWrapper}
* containing the ListView this {@code BaseAdapterDecorator} will be bound
* to.
*/
@Nullable
private ListViewWrapper mListViewWrapper;
/**
* Create a new {@code BaseAdapterDecorator}, decorating given
* {@link android.widget.BaseAdapter}.
*
* @param baseAdapter
* the {@code} BaseAdapter to decorate.
*/
protected BaseAdapterDecorator(@NonNull final BaseAdapter baseAdapter) {
mDecoratedBaseAdapter = baseAdapter;
}
/**
* Returns the {@link android.widget.BaseAdapter} that this
* {@code BaseAdapterDecorator} decorates.
*/
@NonNull
public BaseAdapter getDecoratedBaseAdapter() {
return mDecoratedBaseAdapter;
}
/**
* Returns the root {@link android.widget.BaseAdapter} this
* {@code BaseAdapterDecorator} decorates.
*/
@NonNull
protected BaseAdapter getRootAdapter() {
BaseAdapter adapter = mDecoratedBaseAdapter;
while (adapter instanceof BaseAdapterDecorator) {
adapter = ((BaseAdapterDecorator) adapter)
.getDecoratedBaseAdapter();
}
return adapter;
}
public void setAbsListView(@NonNull final AbsListView absListView) {
setListViewWrapper(new AbsListViewWrapper(absListView));
}
/**
* Returns the {@link com.nhaarman.listviewanimations.util.ListViewWrapper}
* containing the ListView this {@code BaseAdapterDecorator} is bound to.
*/
@Nullable
public ListViewWrapper getListViewWrapper() {
return mListViewWrapper;
}
/**
* Alternative to {@link #setAbsListView(android.widget.AbsListView)}. Sets
* the {@link com.nhaarman.listviewanimations.util.ListViewWrapper} which
* contains the ListView this adapter will be bound to. Call this method
* before setting this adapter to the ListView. Also propagates to the
* decorated {@code BaseAdapter} if applicable.
*/
@Override
public void setListViewWrapper(
@NonNull final ListViewWrapper listViewWrapper) {
mListViewWrapper = listViewWrapper;
if (mDecoratedBaseAdapter instanceof ListViewWrapperSetter) {
((ListViewWrapperSetter) mDecoratedBaseAdapter)
.setListViewWrapper(listViewWrapper);
}
}
@Override
public int getCount() {
return mDecoratedBaseAdapter.getCount();
}
@Override
public Object getItem(final int position) {
return mDecoratedBaseAdapter.getItem(position);
}
@Override
public long getItemId(final int position) {
return mDecoratedBaseAdapter.getItemId(position);
}
@Override
@NonNull
public View getView(final int position, @Nullable final View convertView,
@NonNull final ViewGroup parent) {
return mDecoratedBaseAdapter.getView(position, convertView, parent);
}
@Override
public boolean areAllItemsEnabled() {
return mDecoratedBaseAdapter.areAllItemsEnabled();
}
@Override
@NonNull
public View getDropDownView(final int position,
@Nullable final View convertView, @NonNull final ViewGroup parent) {
return mDecoratedBaseAdapter.getDropDownView(position, convertView,
parent);
}
@Override
public int getItemViewType(final int position) {
return mDecoratedBaseAdapter.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
return mDecoratedBaseAdapter.getViewTypeCount();
}
@Override
public boolean hasStableIds() {
return mDecoratedBaseAdapter.hasStableIds();
}
@Override
public boolean isEmpty() {
return mDecoratedBaseAdapter.isEmpty();
}
@Override
public boolean isEnabled(final int position) {
return mDecoratedBaseAdapter.isEnabled(position);
}
@Override
public void notifyDataSetChanged() {
if (!(mDecoratedBaseAdapter instanceof ArrayAdapter<?>)) {
// fix #35 dirty trick !
// leads to an infinite loop when trying because ArrayAdapter
// triggers notifyDataSetChanged itself
// TODO: investigate
mDecoratedBaseAdapter.notifyDataSetChanged();
}
}
/**
* Helper function if you want to force notifyDataSetChanged()
*/
@SuppressWarnings("UnusedDeclaration")
public void notifyDataSetChanged(final boolean force) {
if (force || !(mDecoratedBaseAdapter instanceof ArrayAdapter<?>)) {
// leads to an infinite loop when trying because ArrayAdapter
// triggers notifyDataSetChanged itself
// TODO: investigate
mDecoratedBaseAdapter.notifyDataSetChanged();
}
}
@Override
public void notifyDataSetInvalidated() {
mDecoratedBaseAdapter.notifyDataSetInvalidated();
}
@Override
public void registerDataSetObserver(@NonNull final DataSetObserver observer) {
mDecoratedBaseAdapter.registerDataSetObserver(observer);
}
@Override
public void unregisterDataSetObserver(
@NonNull final DataSetObserver observer) {
mDecoratedBaseAdapter.unregisterDataSetObserver(observer);
}
@Override
public int getPositionForSection(final int sectionIndex) {
int result = 0;
if (mDecoratedBaseAdapter instanceof SectionIndexer) {
result = ((SectionIndexer) mDecoratedBaseAdapter)
.getPositionForSection(sectionIndex);
}
return result;
}
@Override
public int getSectionForPosition(final int position) {
int result = 0;
if (mDecoratedBaseAdapter instanceof SectionIndexer) {
result = ((SectionIndexer) mDecoratedBaseAdapter)
.getSectionForPosition(position);
}
return result;
}
@Override
@NonNull
public Object[] getSections() {
Object[] result = new Object[0];
if (mDecoratedBaseAdapter instanceof SectionIndexer) {
result = ((SectionIndexer) mDecoratedBaseAdapter).getSections();
}
return result;
}
@Override
public void swapItems(final int positionOne, final int positionTwo) {
if (mDecoratedBaseAdapter instanceof Swappable) {
((Swappable) mDecoratedBaseAdapter).swapItems(positionOne,
positionTwo);
} else {
Log.w("ListViewAnimations",
"Warning: swapItems called on an adapter that does not implement Swappable!");
}
}
@Override
public void add(final int index, @NonNull final Object item) {
if (mDecoratedBaseAdapter instanceof Insertable) {
// noinspection rawtypes
((Insertable) mDecoratedBaseAdapter).add(index, item);
} else {
Log.w("ListViewAnimations",
"Warning: add called on an adapter that does not implement Insertable!");
}
}
}