package org.jsharkey.blog.android;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.SectionIndexer;
/**
* Copyright 2009 Jeffrey Sharkey, 2010 Steve Pomeroy
* Permission is granted to copy, distribute and/or modify this document
* under the terms of the GNU Free Documentation License, Version 1.3
* or any later version published by the Free Software Foundation;
* with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
* A copy of the license is included in the section entitled "GNU
* Free Documentation License".
*
* @author Jeffrey Sharkey
* @author Steve Pomeroy
* @see http://jsharkey.org/blog/2008/08/18/separating-lists-with-headers-in-android-09/
*
*/
public class SeparatedListAdapter extends BaseAdapter implements SectionIndexer {
private final Map<String, SectionHeader> headerMap = new LinkedHashMap<String, SectionHeader>();
private final ArrayAdapter<SectionHeader> headersAdapter;
private final ArrayList<SectionHeader> sections = new ArrayList<SectionHeader>();
public final static int TYPE_SECTION_HEADER = 0;
public SeparatedListAdapter(Context context, int textViewResourceId) {
headersAdapter = new ArrayAdapter<SectionHeader>(context, textViewResourceId, sections);
}
public void addSection(String tag, Adapter adapter) {
addSection(tag, tag, adapter);
}
public void addSection(String tag, String title, Adapter adapter) {
final SectionHeader header = new SectionHeader(tag, title, adapter);
adapter.registerDataSetObserver(new SectionDataSetObserver(header));
this.headersAdapter.add(header);
this.headerMap.put(tag, header);
}
public void setSectionTitle(String tag, String title){
headerMap.get(tag).title = title;
}
public Object getItem(int position) {
for(final SectionHeader section: this.sections) {
final Adapter adapter = section.adapter;
final int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) {
return section;
}
if(position < size) {
return adapter.getItem(position - 1);
}
// otherwise jump into next section
position -= size;
}
return null;
}
public int getCount() {
// total together all sections, plus one for each section header
int total = 0;
for(final SectionHeader section: this.sections) {
final Adapter adapter = section.adapter;
total += adapter.getCount() + 1;
}
return total;
}
@Override
public int getViewTypeCount() {
// assume that headers count as one, then total all sections
int total = 1;
for(final SectionHeader section: this.sections) {
final Adapter adapter = section.adapter;
total += adapter.getViewTypeCount();
}
return total;
}
@Override
public int getItemViewType(int position) {
int type = 1;
for(final SectionHeader section: this.sections) {
final Adapter adapter = section.adapter;
final int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) {
return TYPE_SECTION_HEADER;
}
if(position < size) {
return type + adapter.getItemViewType(position - 1);
}
// otherwise jump into next section
position -= size;
type += adapter.getViewTypeCount();
}
return -1;
}
public boolean areAllItemsSelectable() {
return false;
}
@Override
public boolean isEnabled(int position) {
return (getItemViewType(position) != TYPE_SECTION_HEADER);
}
public View getView(int position, View convertView, ViewGroup parent) {
int sectionnum = 0;
for(final SectionHeader section: this.sections) {
final Adapter adapter = section.adapter;
final int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) {
return headersAdapter.getView(sectionnum, convertView, parent);
}
if(position < size) {
return adapter.getView(position - 1, convertView, parent);
}
// otherwise jump into next section
position -= size;
sectionnum++;
}
return null;
}
public long getItemId(int position) {
for(final SectionHeader section : this.sections) {
final Adapter adapter = section.adapter;
final int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) {
return -1;
}
if(position < size) {
return adapter.getItemId(position - 1);
}
// otherwise jump into next section
position -= size;
}
return -1;
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
super.registerDataSetObserver(observer);
for ( final SectionHeader header: sections){
header.adapter.registerDataSetObserver(observer);
}
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
super.unregisterDataSetObserver(observer);
for ( final SectionHeader header: sections){
header.adapter.unregisterDataSetObserver(observer);
}
}
private class SectionHeader {
public final String tag;
public final Adapter adapter;
public String title;
public int sectionCount;
public SectionHeader(String tag, String title, Adapter adapter) {
this.tag = tag;
this.title = title;
this.adapter = adapter;
this.sectionCount = adapter.getCount();
}
@Override
public String toString() {
return title;
}
}
public int getPositionForSection(int section) {
int position = -1; // offset because we want to return the index of the section header.
for (int i = 0; i < section; i++){
position += sections.get(i).sectionCount + 1;
}
Log.d("foo", "section "+section+"; position: "+position);
return position;
}
public int getSectionForPosition(int position) {
int i = 0;
for(final SectionHeader section : this.sections) {
final int size = section.sectionCount;
// check if position inside this section
if(position == 0) {
return 0;
}
if(position < size) {
Log.d("foo", "section "+i+"; position: "+position);
return i;
}
// otherwise jump into next section
position -= size;
i++;
}
return 0;
}
public Object[] getSections() {
final String[] letters = new String[sections.size()];
for (int i = 0; i < sections.size(); i++){
letters[i] = sections.get(i).title.substring(0, 1);
}
Log.d("foo", "get sections" + letters);
return letters;
}
private class SectionDataSetObserver extends DataSetObserver{
private final SectionHeader header;
public SectionDataSetObserver(SectionHeader header) {
this.header = header;
}
@Override
public void onChanged() {
header.sectionCount = header.adapter.getCount();
}
}
}