Merge commit '42b2e5ca519766e37ce6941ba4faecc9691cc403' into upstream
[debian/openrocket] / android-libraries / TreeViewList / src / pl / polidea / treeview / AbstractTreeViewAdapter.java
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/AbstractTreeViewAdapter.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/AbstractTreeViewAdapter.java
new file mode 100644 (file)
index 0000000..7f2b366
--- /dev/null
@@ -0,0 +1,315 @@
+package pl.polidea.treeview;
+
+import android.app.Activity;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+
+/**
+ * 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 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) {
+        final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
+        if (convertView == null) {
+            final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
+                    getTreeListItemWrapperId(), null);
+            return populateTreeItem(layout, getNewChildView(nodeInfo),
+                    nodeInfo, true);
+        } else {
+            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 FrameLayout.LayoutParams childParams = new FrameLayout.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));
+    }
+
+    private 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);
+    }
+
+}