package com.emilsjolander.components.stickylistheaders;
import java.util.WeakHashMap;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
/**
* A {@link ListAdapter} which wraps a {@link StickyListHeadersAdapter} and
* automatically handles wrapping the result of
* {@link StickyListHeadersAdapter#getView(int, android.view.View, android.view.ViewGroup)}
* and
* {@link StickyListHeadersAdapter#getHeaderView(int, android.view.View, android.view.ViewGroup)}
* appropriately.
*
* @author Jake Wharton (jakewharton@gmail.com)
*/
class StickyListHeadersAdapterWrapper extends BaseAdapter implements
StickyListHeadersAdapter {
static final int VIEW_TYPE_DIVIDER_OFFSET = 1;
static final int VIEW_TYPE_HEADER_OFFSET = 0;
private static final int EXTRA_VIEW_TYPE_COUNT = 2;
private static final int HEADER_POSITION = -1;
private static final int DIVIDER_POSITION = -2;
private final Context context;
final StickyListHeadersAdapter delegate;
private Drawable divider;
private int dividerHeight;
private WeakHashMap<View, Void> headers = new WeakHashMap<View, Void>();
private SparseIntArray positionMapping = new SparseIntArray();
int dividerViewType;
int headerViewType;
private int headerCount;
private int dividerCount;
private int cachedCount = -1;
private DataSetObserver datasetObserver = new DataSetObserver() {
public void onChanged() {
cachedCount = -1;
};
public void onInvalidated() {
cachedCount = -1;
};
};
StickyListHeadersAdapterWrapper(Context context,
StickyListHeadersAdapter delegate) {
this.context = context;
this.delegate = delegate;
registerDataSetObserver(datasetObserver );
}
void setDivider(Drawable divider) {
this.divider = divider;
}
void setDividerHeight(int dividerHeight) {
this.dividerHeight = dividerHeight;
}
boolean isHeader(View v) {
return headers.containsKey(v);
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public boolean isEnabled(int position) {
int viewType = getItemViewType(position);
if (viewType == headerViewType) {
return true;
}else if(viewType == dividerViewType){
return false;
}
position = translateListViewPosition(position);
return delegate.areAllItemsEnabled() || delegate.isEnabled(position);
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
delegate.registerDataSetObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
delegate.unregisterDataSetObserver(observer);
}
@Override
public int getCount() {
//cache the count as it is expensive to count the headers
if(cachedCount<0){
positionMapping.clear();
countHeadersAndUpdatePositionMapping();
cachedCount = delegate.getCount() + headerCount + dividerCount;
}
return cachedCount;
}
private void countHeadersAndUpdatePositionMapping() {
int headerCount = 0;
int dividerCount = 0;
int itemCount = delegate.getCount();
if(itemCount>0){
headerCount++;
long lastHeaderId = delegate.getHeaderId(0);
positionMapping.put(0, HEADER_POSITION);
positionMapping.put(1, 0);
for (int i = 1; i < itemCount; i++) {
long headerId = delegate.getHeaderId(i);
if (lastHeaderId != headerId) {
lastHeaderId = headerId;
positionMapping.put(i + headerCount + dividerCount,
HEADER_POSITION);
headerCount++;
} else {
positionMapping.put(i + headerCount + dividerCount,
DIVIDER_POSITION);
dividerCount++;
}
positionMapping.put(i + headerCount + dividerCount, i);
}
}
this.dividerCount = dividerCount;
this.headerCount = headerCount;
}
int getHeaderCount() {
return headerCount;
}
@Override
public Object getItem(int position) {
int viewType = getItemViewType(position);
if (viewType == headerViewType || viewType == dividerViewType) {
return null;
}
position = translateListViewPosition(position);
return delegate.getItem(position);
}
@Override
public long getItemId(int position) {
if (getItemViewType(position) == headerViewType) {
position = translateListViewPosition(position);
return delegate.getHeaderId(position);
}
position = translateListViewPosition(position);
return delegate.getItemId(position);
}
@Override
public boolean hasStableIds() {
return delegate.hasStableIds();
}
int translateAdapterPosition(int position){
return positionMapping.indexOfValue(position);
}
int translateListViewPosition(int position) {
int viewType = getItemViewType(position);
if (viewType == headerViewType) {
return positionMapping.get(position + 1);
} else if (viewType == dividerViewType) {
return positionMapping.get(position - 1);
} else {
return positionMapping.get(position);
}
}
@Override
public int getItemViewType(int position) {
position = positionMapping.get(position);
if (position == HEADER_POSITION) {
return headerViewType;
}
if (position == DIVIDER_POSITION) {
return dividerViewType;
}
return delegate.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
headerViewType = delegate.getViewTypeCount() + VIEW_TYPE_HEADER_OFFSET;
dividerViewType = delegate.getViewTypeCount()
+ VIEW_TYPE_DIVIDER_OFFSET;
return delegate.getViewTypeCount() + EXTRA_VIEW_TYPE_COUNT;
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final int viewType = getItemViewType(position);
if (viewType == headerViewType) {
headers.remove(convertView);
convertView = delegate
.getHeaderView(
translateListViewPosition(position),
convertView, parent);
headers.put(convertView, null);
} else if (viewType == dividerViewType) {
if (convertView == null) {
convertView = makeDivider();
}
return convertView;
} else {
convertView = delegate.getView(
translateListViewPosition(position),
convertView, parent);
}
return convertView;
}
@SuppressWarnings("deprecation")
private View makeDivider() {
View v = new View(context);
v.setBackgroundDrawable(divider);
AbsListView.LayoutParams params = new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT, dividerHeight);
v.setLayoutParams(params);
return v;
}
@Override
public boolean equals(Object o) {
return delegate.equals(o);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == headerViewType) {
return null;
}
position = translateListViewPosition(position);
return ((BaseAdapter) delegate).getDropDownView(position, convertView,
parent);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public void notifyDataSetChanged() {
((BaseAdapter) delegate).notifyDataSetChanged();
}
@Override
public void notifyDataSetInvalidated() {
((BaseAdapter) delegate).notifyDataSetInvalidated();
}
@Override
public String toString() {
return delegate.toString();
}
@Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
return delegate.getHeaderView(
translateListViewPosition(position),
convertView, parent);
}
@Override
public long getHeaderId(int position) {
return delegate
.getHeaderId(translateListViewPosition(position));
}
StickyListHeadersAdapter getDelegate() {
return delegate;
}
}