You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
7.2 KiB
315 lines
7.2 KiB
11 years ago
|
/*
|
||
|
* Copyright 2010-2013 Eric Kok et al.
|
||
|
*
|
||
|
* Transdroid is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Transdroid is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
11 years ago
|
package org.transdroid.core.gui.lists;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
|
||
|
import android.database.DataSetObserver;
|
||
|
import android.view.View;
|
||
|
import android.view.ViewGroup;
|
||
|
import android.widget.Adapter;
|
||
|
import android.widget.BaseAdapter;
|
||
|
import android.widget.ListAdapter;
|
||
|
import android.widget.SectionIndexer;
|
||
|
import android.widget.TextView;
|
||
|
|
||
|
/**
|
||
|
* An adapter that can contain many other adapters and shows them in sequence. Taken from
|
||
|
* http://stackoverflow.com/questions/7964259/android-attaching-multiple-adapters-to-one-adapter and based on the Apache
|
||
|
* 2-licensed CommonsWare MergeAdapter.
|
||
|
* @author Eric Kok
|
||
|
* @author Alex Amiryan
|
||
|
* @author Mark Murphy
|
||
|
*/
|
||
|
public class MergeAdapter extends BaseAdapter implements SectionIndexer {
|
||
|
|
||
|
protected ArrayList<ListAdapter> pieces = new ArrayList<ListAdapter>();
|
||
|
protected String noItemsText;
|
||
|
|
||
|
/**
|
||
|
* Stock constructor, simply chaining to the superclass.
|
||
|
*/
|
||
|
public MergeAdapter() {
|
||
|
super();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Adds a new adapter to the roster of things to appear in the aggregate list.
|
||
|
* @param adapter Source for row views for this section
|
||
|
*/
|
||
|
public void addAdapter(ListAdapter adapter) {
|
||
|
pieces.add(adapter);
|
||
|
adapter.registerDataSetObserver(new CascadeDataSetObserver());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the data item associated with the specified position in the data set.
|
||
|
* @param position Position of the item whose data we want
|
||
|
*/
|
||
|
public Object getItem(int position) {
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
return (piece.getItem(position));
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
return (null);
|
||
|
}
|
||
|
|
||
|
public void setNoItemsText(String text) {
|
||
|
noItemsText = text;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the adapter associated with the specified position in the data set.
|
||
|
* @param position Position of the item whose adapter we want
|
||
|
*/
|
||
|
public ListAdapter getAdapter(int position) {
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
return (piece);
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
return (null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* How many items are in the data set represented by this {@link Adapter}.
|
||
|
*/
|
||
|
public int getCount() {
|
||
|
int total = 0;
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
total += piece.getCount();
|
||
|
}
|
||
|
|
||
|
if (total == 0 && noItemsText != null) {
|
||
|
total = 1;
|
||
|
}
|
||
|
|
||
|
return (total);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the number of types of {@link View}s that will be created by {@link #getView(int, View, ViewGroup)}.
|
||
|
*/
|
||
|
@Override
|
||
|
public int getViewTypeCount() {
|
||
|
int total = 0;
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
total += piece.getViewTypeCount();
|
||
|
}
|
||
|
|
||
|
return (Math.max(total, 1)); // needed for setListAdapter() before
|
||
|
// content add'
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the type of {@link View} that will be created by {@link #getView(int, View, ViewGroup)} for the specified item.
|
||
|
* @param position Position of the item whose data we want
|
||
|
*/
|
||
|
@Override
|
||
|
public int getItemViewType(int position) {
|
||
|
int typeOffset = 0;
|
||
|
int result = -1;
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
result = typeOffset + piece.getItemViewType(position);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
typeOffset += piece.getViewTypeCount();
|
||
|
}
|
||
|
|
||
|
return (result);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Are all items in this {@link ListAdapter} enabled? If yes it means all items are selectable and clickable.
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean areAllItemsEnabled() {
|
||
|
return (false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the item at the specified position is not a separator.
|
||
|
* @param position Position of the item whose data we want
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean isEnabled(int position) {
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
return (piece.isEnabled(position));
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
return (false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get a {@link View} that displays the data at the specified position in the data set.
|
||
|
* @param position Position of the item whose data we want
|
||
|
* @param convertView View to recycle, if not null
|
||
|
* @param parent ViewGroup containing the returned View
|
||
|
*/
|
||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
|
||
|
return (piece.getView(position, convertView, parent));
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
if (noItemsText != null) {
|
||
|
TextView text = new TextView(parent.getContext());
|
||
|
text.setText(noItemsText);
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
return (null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the row id associated with the specified position in the list.
|
||
|
* @param position Position of the item whose data we want
|
||
|
*/
|
||
|
public long getItemId(int position) {
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
return (piece.getItemId(position));
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
public final int getPositionForSection(int section) {
|
||
|
int position = 0;
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
if (piece instanceof SectionIndexer) {
|
||
|
Object[] sections = ((SectionIndexer) piece).getSections();
|
||
|
int numSections = 0;
|
||
|
|
||
|
if (sections != null) {
|
||
|
numSections = sections.length;
|
||
|
}
|
||
|
|
||
|
if (section < numSections) {
|
||
|
return (position + ((SectionIndexer) piece).getPositionForSection(section));
|
||
|
} else if (sections != null) {
|
||
|
section -= numSections;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
position += piece.getCount();
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
public final int getSectionForPosition(int position) {
|
||
|
int section = 0;
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
int size = piece.getCount();
|
||
|
|
||
|
if (position < size) {
|
||
|
if (piece instanceof SectionIndexer) {
|
||
|
return (section + ((SectionIndexer) piece).getSectionForPosition(position));
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
} else {
|
||
|
if (piece instanceof SectionIndexer) {
|
||
|
Object[] sections = ((SectionIndexer) piece).getSections();
|
||
|
|
||
|
if (sections != null) {
|
||
|
section += sections.length;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
position -= size;
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
public final Object[] getSections() {
|
||
|
ArrayList<Object> sections = new ArrayList<Object>();
|
||
|
|
||
|
for (ListAdapter piece : pieces) {
|
||
|
if (piece instanceof SectionIndexer) {
|
||
|
Object[] curSections = ((SectionIndexer) piece).getSections();
|
||
|
|
||
|
if (curSections != null) {
|
||
|
for (Object section : curSections) {
|
||
|
sections.add(section);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (sections.size() == 0) {
|
||
|
return (null);
|
||
|
}
|
||
|
|
||
|
return (sections.toArray(new Object[0]));
|
||
|
}
|
||
|
|
||
|
private class CascadeDataSetObserver extends DataSetObserver {
|
||
|
@Override
|
||
|
public void onChanged() {
|
||
|
notifyDataSetChanged();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void onInvalidated() {
|
||
|
notifyDataSetInvalidated();
|
||
|
}
|
||
|
}
|
||
|
|
||
11 years ago
|
}
|