1 package pl.polidea.treeview;
3 import net.sf.openrocket.R;
4 import android.app.Activity;
5 import android.content.Context;
6 import android.database.DataSetObserver;
7 import android.graphics.drawable.Drawable;
8 import android.view.LayoutInflater;
9 import android.view.View;
10 import android.view.View.OnClickListener;
11 import android.view.ViewGroup;
12 import android.widget.BaseAdapter;
13 import android.widget.FrameLayout;
14 import android.widget.FrameLayout.LayoutParams;
15 import android.widget.ImageView;
16 import android.widget.ImageView.ScaleType;
17 import android.widget.LinearLayout;
18 import android.widget.ListAdapter;
21 * Adapter used to feed the table view.
24 * class for ID of the tree
26 public abstract class AbstractTreeViewAdapter<T> extends BaseAdapter implements
28 private final TreeStateManager<T> treeStateManager;
29 private final int numberOfLevels;
30 private final LayoutInflater layoutInflater;
32 private int indentWidth = 0;
33 private int indicatorGravity = 0;
34 private Drawable collapsedDrawable;
35 private Drawable expandedDrawable;
36 private Drawable indicatorBackgroundDrawable;
37 private Drawable rowBackgroundDrawable;
39 private final OnClickListener indicatorClickListener = new OnClickListener() {
41 public void onClick(final View v) {
42 @SuppressWarnings("unchecked")
43 final T id = (T) v.getTag();
48 private boolean collapsible;
49 private final Activity activity;
51 public Activity getActivity() {
55 protected TreeStateManager<T> getManager() {
56 return treeStateManager;
59 protected void expandCollapse(final T id) {
60 final TreeNodeInfo<T> info = treeStateManager.getNodeInfo(id);
61 if (!info.isWithChildren()) {
62 // ignore - no default action
65 if (info.isExpanded()) {
66 treeStateManager.collapseChildren(id);
68 treeStateManager.expandDirectChildren(id);
72 private void calculateIndentWidth() {
73 if (expandedDrawable != null) {
74 indentWidth = Math.max(getIndentWidth(),
75 expandedDrawable.getIntrinsicWidth());
77 if (collapsedDrawable != null) {
78 indentWidth = Math.max(getIndentWidth(),
79 collapsedDrawable.getIntrinsicWidth());
83 public AbstractTreeViewAdapter(final Activity activity,
84 final TreeStateManager<T> treeStateManager, final int numberOfLevels) {
85 this.activity = activity;
86 this.treeStateManager = treeStateManager;
87 this.layoutInflater = (LayoutInflater) activity
88 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
89 this.numberOfLevels = numberOfLevels;
90 this.collapsedDrawable = null;
91 this.expandedDrawable = null;
92 this.rowBackgroundDrawable = null;
93 this.indicatorBackgroundDrawable = null;
97 public void registerDataSetObserver(final DataSetObserver observer) {
98 treeStateManager.registerDataSetObserver(observer);
102 public void unregisterDataSetObserver(final DataSetObserver observer) {
103 treeStateManager.unregisterDataSetObserver(observer);
107 public int getCount() {
108 return treeStateManager.getVisibleCount();
112 public Object getItem(final int position) {
113 return getItemId(position);
116 public T getTreeId(final int position) {
117 return treeStateManager.getVisibleList().get(position);
120 public TreeNodeInfo<T> getTreeNodeInfo(final int position) {
121 return treeStateManager.getNodeInfo(getTreeId(position));
125 public boolean hasStableIds() { // NOPMD
130 public int getItemViewType(final int position) {
131 return getTreeNodeInfo(position).getLevel();
135 public int getViewTypeCount() {
136 return numberOfLevels;
140 public boolean isEmpty() {
141 return getCount() == 0;
145 public boolean areAllItemsEnabled() { // NOPMD
150 public boolean isEnabled(final int position) { // NOPMD
154 protected int getTreeListItemWrapperId() {
155 return R.layout.tree_list_item_wrapper;
159 public final View getView(final int position, final View convertView,
160 final ViewGroup parent) {
161 final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
162 if (convertView == null) {
163 final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
164 getTreeListItemWrapperId(), null);
165 return populateTreeItem(layout, getNewChildView(nodeInfo),
168 final LinearLayout linear = (LinearLayout) convertView;
169 final FrameLayout frameLayout = (FrameLayout) linear
170 .findViewById(R.id.treeview_list_item_frame);
171 final View childView = frameLayout.getChildAt(0);
172 updateView(childView, nodeInfo);
173 return populateTreeItem(linear, childView, nodeInfo, false);
178 * Called when new view is to be created.
180 * @param treeNodeInfo
182 * @return view that should be displayed as tree content
184 public abstract View getNewChildView(TreeNodeInfo<T> treeNodeInfo);
187 * Called when new view is going to be reused. You should update the view
188 * and fill it in with the data required to display the new information. You
189 * can also create a new view, which will mean that the old view will not be
193 * view that should be updated with the new values
194 * @param treeNodeInfo
195 * node info used to populate the view
196 * @return view to used as row indented content
198 public abstract View updateView(View view, TreeNodeInfo<T> treeNodeInfo);
201 * Retrieves background drawable for the node.
203 * @param treeNodeInfo
205 * @return drawable returned as background for the whole row. Might be null,
206 * then default background is used
208 public Drawable getBackgroundDrawable(final TreeNodeInfo<T> treeNodeInfo) { // NOPMD
212 private Drawable getDrawableOrDefaultBackground(final Drawable r) {
214 return activity.getResources()
215 .getDrawable(R.drawable.list_selector_background).mutate();
221 public final LinearLayout populateTreeItem(final LinearLayout layout,
222 final View childView, final TreeNodeInfo<T> nodeInfo,
223 final boolean newChildView) {
224 final Drawable individualRowDrawable = getBackgroundDrawable(nodeInfo);
225 layout.setBackgroundDrawable(individualRowDrawable == null ? getDrawableOrDefaultBackground(rowBackgroundDrawable)
226 : individualRowDrawable);
227 final LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
228 calculateIndentation(nodeInfo), LayoutParams.FILL_PARENT);
229 final LinearLayout indicatorLayout = (LinearLayout) layout
230 .findViewById(R.id.treeview_list_item_image_layout);
231 indicatorLayout.setGravity(indicatorGravity);
232 indicatorLayout.setLayoutParams(indicatorLayoutParams);
233 final ImageView image = (ImageView) layout
234 .findViewById(R.id.treeview_list_item_image);
235 image.setImageDrawable(getDrawable(nodeInfo));
236 image.setBackgroundDrawable(getDrawableOrDefaultBackground(indicatorBackgroundDrawable));
237 image.setScaleType(ScaleType.CENTER);
238 image.setTag(nodeInfo.getId());
239 if (nodeInfo.isWithChildren() && collapsible) {
240 image.setOnClickListener(indicatorClickListener);
242 image.setOnClickListener(null);
244 layout.setTag(nodeInfo.getId());
245 final FrameLayout frameLayout = (FrameLayout) layout
246 .findViewById(R.id.treeview_list_item_frame);
247 final FrameLayout.LayoutParams childParams = new FrameLayout.LayoutParams(
248 LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
250 frameLayout.addView(childView, childParams);
252 frameLayout.setTag(nodeInfo.getId());
256 protected int calculateIndentation(final TreeNodeInfo<T> nodeInfo) {
257 return getIndentWidth() * (nodeInfo.getLevel() + (collapsible ? 1 : 0));
260 private Drawable getDrawable(final TreeNodeInfo<T> nodeInfo) {
261 if (!nodeInfo.isWithChildren() || !collapsible) {
262 return getDrawableOrDefaultBackground(indicatorBackgroundDrawable);
264 if (nodeInfo.isExpanded()) {
265 return expandedDrawable;
267 return collapsedDrawable;
271 public void setIndicatorGravity(final int indicatorGravity) {
272 this.indicatorGravity = indicatorGravity;
275 public void setCollapsedDrawable(final Drawable collapsedDrawable) {
276 this.collapsedDrawable = collapsedDrawable;
277 calculateIndentWidth();
280 public void setExpandedDrawable(final Drawable expandedDrawable) {
281 this.expandedDrawable = expandedDrawable;
282 calculateIndentWidth();
285 public void setIndentWidth(final int indentWidth) {
286 this.indentWidth = indentWidth;
287 calculateIndentWidth();
290 public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
291 this.rowBackgroundDrawable = rowBackgroundDrawable;
294 public void setIndicatorBackgroundDrawable(
295 final Drawable indicatorBackgroundDrawable) {
296 this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
299 public void setCollapsible(final boolean collapsible) {
300 this.collapsible = collapsible;
303 public void refresh() {
304 treeStateManager.refresh();
307 private int getIndentWidth() {
311 @SuppressWarnings("unchecked")
312 public void handleItemClick(final View view, final Object id) {
313 expandCollapse((T) id);