package com.pl.polidea.treeview;
import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.*;
import android.widget.FrameLayout.LayoutParams;
import android.widget.ImageView.ScaleType;
import com.silverkeytech.android_rivers.R;
/**
* Adapter used to feed the table view.
*
* @param <T>
* class for ID of the tree
*/
public abstract class AbstractTreeViewAdapter<T> extends BaseAdapter implements
ListAdapter {
private static final String TAG = AbstractTreeViewAdapter.class
.getSimpleName();
private final TreeStateManager<T> treeStateManager;
private final int numberOfLevels;
private final LayoutInflater layoutInflater;
private int indentWidth = 0;
private int indicatorGravity = 0;
private Drawable collapsedDrawable;
private Drawable expandedDrawable;
private Drawable indicatorBackgroundDrawable;
private Drawable rowBackgroundDrawable;
private final OnClickListener indicatorClickListener = new OnClickListener() {
@Override
public void onClick(final View v) {
@SuppressWarnings("unchecked")
final T id = (T) v.getTag();
expandCollapse(id);
}
};
private boolean collapsible;
private final Activity activity;
public Activity getActivity() {
return activity;
}
protected TreeStateManager<T> getManager() {
return treeStateManager;
}
protected void expandCollapse(final T id) {
final TreeNodeInfo<T> info = treeStateManager.getNodeInfo(id);
if (!info.isWithChildren()) {
// ignore - no default action
return;
}
if (info.isExpanded()) {
treeStateManager.collapseChildren(id);
} else {
treeStateManager.expandDirectChildren(id);
}
}
private void calculateIndentWidth() {
if (expandedDrawable != null) {
indentWidth = Math.max(getIndentWidth(),
expandedDrawable.getIntrinsicWidth());
}
if (collapsedDrawable != null) {
indentWidth = Math.max(getIndentWidth(),
collapsedDrawable.getIntrinsicWidth());
}
}
public AbstractTreeViewAdapter(final Activity activity,
final TreeStateManager<T> treeStateManager, final int numberOfLevels) {
this.activity = activity;
this.treeStateManager = treeStateManager;
this.layoutInflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.numberOfLevels = numberOfLevels;
this.collapsedDrawable = null;
this.expandedDrawable = null;
this.rowBackgroundDrawable = null;
this.indicatorBackgroundDrawable = null;
}
@Override
public void registerDataSetObserver(final DataSetObserver observer) {
treeStateManager.registerDataSetObserver(observer);
}
@Override
public void unregisterDataSetObserver(final DataSetObserver observer) {
treeStateManager.unregisterDataSetObserver(observer);
}
@Override
public int getCount() {
return treeStateManager.getVisibleCount();
}
@Override
public Object getItem(final int position) {
return getItemId(position);
}
public T getTreeId(final int position) {
return treeStateManager.getVisibleList().get(position);
}
public TreeNodeInfo<T> getTreeNodeInfo(final int position) {
return treeStateManager.getNodeInfo(getTreeId(position));
}
@Override
public boolean hasStableIds() { // NOPMD
return true;
}
@Override
public int getItemViewType(final int position) {
return getTreeNodeInfo(position).getLevel();
}
@Override
public int getViewTypeCount() {
return numberOfLevels;
}
@Override
public boolean isEmpty() {
return getCount() == 0;
}
@Override
public boolean areAllItemsEnabled() { // NOPMD
return true;
}
@Override
public boolean isEnabled(final int position) { // NOPMD
return true;
}
protected int getTreeListItemWrapperId() {
return R.layout.tree_list_item_wrapper;
}
@Override
public final View getView(final int position, final View convertView,
final ViewGroup parent) {
Log.d(TAG, "Creating a view based on " + convertView
+ " with position " + position);
final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
if (convertView == null) {
Log.d(TAG, "Creating the view a new");
final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
getTreeListItemWrapperId(), null);
return populateTreeItem(layout, getNewChildView(nodeInfo),
nodeInfo, true);
} else {
Log.d(TAG, "Reusing the view");
final LinearLayout linear = (LinearLayout) convertView;
final FrameLayout frameLayout = (FrameLayout) linear
.findViewById(R.id.treeview_list_item_frame);
final View childView = frameLayout.getChildAt(0);
updateView(childView, nodeInfo);
return populateTreeItem(linear, childView, nodeInfo, false);
}
}
/**
* Called when new view is to be created.
*
* @param treeNodeInfo
* node info
* @return view that should be displayed as tree content
*/
public abstract View getNewChildView(TreeNodeInfo<T> treeNodeInfo);
/**
* Called when new view is going to be reused. You should update the view
* and fill it in with the data required to display the new information. You
* can also create a new view, which will mean that the old view will not be
* reused.
*
* @param view
* view that should be updated with the new values
* @param treeNodeInfo
* node info used to populate the view
* @return view to used as row indented content
*/
public abstract View updateView(View view, TreeNodeInfo<T> treeNodeInfo);
/**
* Retrieves background drawable for the node.
*
* @param treeNodeInfo
* node info
* @return drawable returned as background for the whole row. Might be null,
* then default background is used
*/
public Drawable getBackgroundDrawable(final TreeNodeInfo<T> treeNodeInfo) { // NOPMD
return null;
}
private Drawable getDrawableOrDefaultBackground(final Drawable r) {
if (r == null) {
return activity.getResources()
.getDrawable(R.drawable.list_selector_background).mutate();
} else {
return r;
}
}
public final LinearLayout populateTreeItem(final LinearLayout layout,
final View childView, final TreeNodeInfo<T> nodeInfo,
final boolean newChildView) {
final Drawable individualRowDrawable = getBackgroundDrawable(nodeInfo);
layout.setBackgroundDrawable(individualRowDrawable == null ? getDrawableOrDefaultBackground(rowBackgroundDrawable)
: individualRowDrawable);
final LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
calculateIndentation(nodeInfo), LayoutParams.FILL_PARENT);
final LinearLayout indicatorLayout = (LinearLayout) layout
.findViewById(R.id.treeview_list_item_image_layout);
indicatorLayout.setGravity(indicatorGravity);
indicatorLayout.setLayoutParams(indicatorLayoutParams);
final ImageView image = (ImageView) layout
.findViewById(R.id.treeview_list_item_image);
image.setImageDrawable(getDrawable(nodeInfo));
image.setBackgroundDrawable(getDrawableOrDefaultBackground(indicatorBackgroundDrawable));
image.setScaleType(ScaleType.CENTER);
image.setTag(nodeInfo.getId());
if (nodeInfo.isWithChildren() && collapsible) {
image.setOnClickListener(indicatorClickListener);
} else {
image.setOnClickListener(null);
}
layout.setTag(nodeInfo.getId());
final FrameLayout frameLayout = (FrameLayout) layout
.findViewById(R.id.treeview_list_item_frame);
final LayoutParams childParams = new LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
if (newChildView) {
frameLayout.addView(childView, childParams);
}
frameLayout.setTag(nodeInfo.getId());
return layout;
}
protected int calculateIndentation(final TreeNodeInfo<T> nodeInfo) {
return getIndentWidth() * (nodeInfo.getLevel() + (collapsible ? 1 : 0));
}
protected Drawable getDrawable(final TreeNodeInfo<T> nodeInfo) {
if (!nodeInfo.isWithChildren() || !collapsible) {
return getDrawableOrDefaultBackground(indicatorBackgroundDrawable);
}
if (nodeInfo.isExpanded()) {
return expandedDrawable;
} else {
return collapsedDrawable;
}
}
public void setIndicatorGravity(final int indicatorGravity) {
this.indicatorGravity = indicatorGravity;
}
public void setCollapsedDrawable(final Drawable collapsedDrawable) {
this.collapsedDrawable = collapsedDrawable;
calculateIndentWidth();
}
public void setExpandedDrawable(final Drawable expandedDrawable) {
this.expandedDrawable = expandedDrawable;
calculateIndentWidth();
}
public void setIndentWidth(final int indentWidth) {
this.indentWidth = indentWidth;
calculateIndentWidth();
}
public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
this.rowBackgroundDrawable = rowBackgroundDrawable;
}
public void setIndicatorBackgroundDrawable(
final Drawable indicatorBackgroundDrawable) {
this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
}
public void setCollapsible(final boolean collapsible) {
this.collapsible = collapsible;
}
public void refresh() {
treeStateManager.refresh();
}
private int getIndentWidth() {
return indentWidth;
}
@SuppressWarnings("unchecked")
public void handleItemClick(final View view, final Object id) {
expandCollapse((T) id);
}
}