+package net.sf.openrocket.android.util;\r
+\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.support.v4.app.Fragment;\r
+import android.view.ContextMenu;\r
+import android.view.ContextMenu.ContextMenuInfo;\r
+import android.view.Gravity;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnCreateContextMenuListener;\r
+import android.view.ViewGroup;\r
+import android.view.animation.AnimationUtils;\r
+import android.widget.AdapterView;\r
+import android.widget.ExpandableListAdapter;\r
+import android.widget.ExpandableListView;\r
+import android.widget.FrameLayout;\r
+import android.widget.ListAdapter;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+\r
+/**\r
+ * \r
+ * Pulled from https://gist.github.com/1316903\r
+ * \r
+ * This class has originally been taken from\r
+ * http://stackoverflow.com/questions/6051050/expandablelistfragment-with-loadermanager-for-compatibility-package\r
+ * and then modified by Manfred Moser <manfred@simpligility.com> to get it to work with the v4 r4 compatibility\r
+ * library. With inspirations from the library source.\r
+ *\r
+ * All ASLv2 licensed.\r
+ */\r
+public class ExpandableListFragment extends Fragment\r
+implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener,\r
+ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener\r
+{\r
+\r
+ static final int INTERNAL_EMPTY_ID = 0x00ff0001;\r
+ static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;\r
+\r
+ final private Handler mHandler = new Handler();\r
+\r
+ final private Runnable mRequestFocus = new Runnable() {\r
+ public void run() {\r
+ mList.focusableViewAvailable(mList);\r
+ }\r
+ };\r
+\r
+ final private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {\r
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {\r
+ onListItemClick((ListView) parent, v, position, id);\r
+ }\r
+ };\r
+\r
+ ExpandableListAdapter mAdapter;\r
+ ExpandableListView mList;\r
+ View mEmptyView;\r
+ TextView mStandardEmptyView;\r
+ View mListContainer;\r
+ boolean mSetEmptyText;\r
+ boolean mListShown;\r
+ boolean mFinishedStart = false;\r
+\r
+ public ExpandableListFragment() {\r
+ }\r
+\r
+ /**\r
+ * Provide default implementation to return a simple list view. Subclasses\r
+ * can override to replace with their own layout. If doing so, the\r
+ * returned view hierarchy <em>must</em> have a ListView whose id\r
+ * is {@link android.R.id#list android.R.id.list} and can optionally\r
+ * have a sibling view id {@link android.R.id#empty android.R.id.empty}\r
+ * that is to be shown when the list is empty.\r
+ * <p/>\r
+ * <p>If you are overriding this method with your own custom content,\r
+ * consider including the standard layout {@link android.R.layout#list_content}\r
+ * in your layout file, so that you continue to retain all of the standard\r
+ * behavior of ListFragment. In particular, this is currently the only\r
+ * way to have the built-in indeterminant progress state be shown.\r
+ */\r
+ @Override\r
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
+ FrameLayout root = new FrameLayout(getActivity());\r
+\r
+ FrameLayout lframe = new FrameLayout(getActivity());\r
+ lframe.setId(INTERNAL_LIST_CONTAINER_ID);\r
+\r
+ TextView tv = new TextView(getActivity());\r
+ tv.setId(INTERNAL_EMPTY_ID);\r
+ tv.setGravity(Gravity.CENTER);\r
+ lframe.addView(tv,\r
+ new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+ ExpandableListView lv = new ExpandableListView(getActivity());\r
+ lv.setId(android.R.id.list);\r
+ lv.setDrawSelectorOnTop(false);\r
+ lv.setOnChildClickListener(this);\r
+ lv.setOnGroupExpandListener(this);\r
+ lv.setOnGroupCollapseListener(this);\r
+\r
+ lframe.addView(lv,\r
+ new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+ root.addView(lframe, new FrameLayout.LayoutParams(\r
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));\r
+\r
+ ListView.LayoutParams lp =\r
+ new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);\r
+ root.setLayoutParams(lp);\r
+\r
+ return root;\r
+ }\r
+\r
+ /**\r
+ * Attach to list view once the view hierarchy has been created.\r
+ */\r
+ @Override\r
+ public void onViewCreated(View view, Bundle savedInstanceState) {\r
+ super.onViewCreated(view, savedInstanceState);\r
+ ensureList();\r
+ }\r
+\r
+ /** Detach from list view. */\r
+ @Override\r
+ public void onDestroyView() {\r
+ mHandler.removeCallbacks(mRequestFocus);\r
+ mList = null;\r
+ super.onDestroyView();\r
+ }\r
+\r
+ /**\r
+ * This method will be called when an item in the list is selected.\r
+ * Subclasses should override. Subclasses can call\r
+ * getListView().getItemAtPosition(position) if they need to access the\r
+ * data associated with the selected item.\r
+ * @param l The ListView where the click happened\r
+ * @param v The view that was clicked within the ListView\r
+ * @param position The position of the view in the list\r
+ * @param id The row id of the item that was clicked\r
+ */\r
+ public void onListItemClick(ListView l, View v, int position, long id) {\r
+ }\r
+\r
+ /** Provide the cursor for the list view. */\r
+ public void setListAdapter(ExpandableListAdapter adapter) {\r
+ boolean hadAdapter = mAdapter != null;\r
+ mAdapter = adapter;\r
+ if (mList != null) {\r
+ mList.setAdapter((ExpandableListAdapter) null);\r
+ mList.setAdapter(adapter);\r
+ if (!mListShown && !hadAdapter) {\r
+ // The list was hidden, and previously didn't have an\r
+ // adapter. It is now time to show it.\r
+ setListShown(true, getView().getWindowToken() != null);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the currently selected list item to the specified\r
+ * position with the adapter's data\r
+ */\r
+ public void setSelection(int position) {\r
+ ensureList();\r
+ mList.setSelection(position);\r
+ }\r
+\r
+ public long getSelectedPosition() {\r
+ ensureList();\r
+ return mList.getSelectedPosition();\r
+ }\r
+\r
+ public long getSelectedId() {\r
+ ensureList();\r
+ return mList.getSelectedId();\r
+ }\r
+\r
+ public ExpandableListView getExpandableListView() {\r
+ ensureList();\r
+ return mList;\r
+ }\r
+\r
+ /**\r
+ * The default content for a ListFragment has a TextView that can\r
+ * be shown when the list is empty. If you would like to have it\r
+ * shown, call this method to supply the text it should use.\r
+ */\r
+ public void setEmptyText(CharSequence text) {\r
+ ensureList();\r
+ if (mStandardEmptyView == null) {\r
+ throw new IllegalStateException("Can't be used with a custom content view");\r
+ }\r
+ mStandardEmptyView.setText(text);\r
+ if (!mSetEmptyText) {\r
+ mList.setEmptyView(mStandardEmptyView);\r
+ mSetEmptyText = true;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Control whether the list is being displayed. You can make it not\r
+ * displayed if you are waiting for the initial data to show in it. During\r
+ * this time an indeterminant progress indicator will be shown instead.\r
+ * <p/>\r
+ * <p>Applications do not normally need to use this themselves. The default\r
+ * behavior of ListFragment is to start with the list not being shown, only\r
+ * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}.\r
+ * If the list at that point had not been shown, when it does get shown\r
+ * it will be do without the user ever seeing the hidden state.\r
+ * @param shown If true, the list view is shown; if false, the progress\r
+ * indicator. The initial value is true.\r
+ */\r
+ public void setListShown(boolean shown) {\r
+ setListShown(shown, true);\r
+ }\r
+\r
+ /**\r
+ * Like {@link #setListShown(boolean)}, but no animation is used when\r
+ * transitioning from the previous state.\r
+ */\r
+ public void setListShownNoAnimation(boolean shown) {\r
+ setListShown(shown, false);\r
+ }\r
+\r
+ /**\r
+ * Control whether the list is being displayed. You can make it not\r
+ * displayed if you are waiting for the initial data to show in it. During\r
+ * this time an indeterminant progress indicator will be shown instead.\r
+ * @param shown If true, the list view is shown; if false, the progress\r
+ * indicator. The initial value is true.\r
+ * @param animate If true, an animation will be used to transition to the\r
+ * new state.\r
+ */\r
+ private void setListShown(boolean shown, boolean animate) {\r
+ ensureList();\r
+ if (mListShown == shown) {\r
+ return;\r
+ }\r
+ mListShown = shown;\r
+ if (mListContainer != null) {\r
+ if (shown) {\r
+ if (animate) {\r
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in));\r
+ }\r
+ mListContainer.setVisibility(View.VISIBLE);\r
+ } else {\r
+ if (animate) {\r
+ mListContainer.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out));\r
+ }\r
+ mListContainer.setVisibility(View.GONE);\r
+ }\r
+ }\r
+ }\r
+\r
+ /** Get the ListAdapter associated with this activity's ListView. */\r
+ public ExpandableListAdapter getExpandableListAdapter() {\r
+ return mAdapter;\r
+ }\r
+\r
+ private void ensureList() {\r
+ if (mList != null) {\r
+ return;\r
+ }\r
+ View root = getView();\r
+ if (root == null) {\r
+ throw new IllegalStateException("Content view not yet created");\r
+ }\r
+ if (root instanceof ExpandableListView) {\r
+ mList = (ExpandableListView) root;\r
+ } else {\r
+ mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID);\r
+ if (mStandardEmptyView == null) {\r
+ mEmptyView = root.findViewById(android.R.id.empty);\r
+ }\r
+ mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);\r
+ View rawListView = root.findViewById(android.R.id.list);\r
+ if (!(rawListView instanceof ExpandableListView)) {\r
+ if (rawListView == null) {\r
+ throw new RuntimeException("Your content must have a ExpandableListView whose id attribute is " +\r
+ "'android.R.id.list'");\r
+ }\r
+ throw new RuntimeException("Content has view with id attribute 'android.R.id.list' " +\r
+ "that is not a ExpandableListView class");\r
+ }\r
+ mList = (ExpandableListView) rawListView;\r
+ if (mEmptyView != null) {\r
+ mList.setEmptyView(mEmptyView);\r
+ }\r
+ }\r
+ mListShown = true;\r
+ mList.setOnItemClickListener(mOnClickListener);\r
+ if (mAdapter != null) {\r
+ setListAdapter(mAdapter);\r
+ } else {\r
+ // We are starting without an adapter, so assume we won't\r
+ // have our data right away and start with the progress indicator.\r
+ setListShown(false, false);\r
+ }\r
+ mHandler.post(mRequestFocus);\r
+ }\r
+\r
+ @Override\r
+ public void onGroupExpand(int arg0) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public void onGroupCollapse(int arg0) {\r
+ // TODO Auto-generated method stub\r
+\r
+ }\r
+\r
+ @Override\r
+ public boolean onChildClick(ExpandableListView arg0, View arg1, int arg2, int arg3, long arg4) {\r
+ // TODO Auto-generated method stub\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\r
+ }\r
+\r
+ public void onContentChanged() {\r
+ View emptyView = getView().findViewById(android.R.id.empty);\r
+ mList = (ExpandableListView) getView().findViewById(android.R.id.list);\r
+ if (mList == null) {\r
+ throw new RuntimeException(\r
+ "Your content must have a ExpandableListView whose id attribute is " + "'android.R.id.list'");\r
+ }\r
+ if (emptyView != null) {\r
+ mList.setEmptyView(emptyView);\r
+ }\r
+ mList.setOnChildClickListener(this);\r
+ mList.setOnGroupExpandListener(this);\r
+ mList.setOnGroupCollapseListener(this);\r
+\r
+ if (mFinishedStart) {\r
+ setListAdapter(mAdapter);\r
+ }\r
+ mFinishedStart = true;\r
+ }\r
+}\r
+\r