Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/ExpandableListConnector.java')
-rw-r--r--android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/ExpandableListConnector.java594
1 files changed, 594 insertions, 0 deletions
diff --git a/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/ExpandableListConnector.java b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/ExpandableListConnector.java
new file mode 100644
index 0000000000..65c28c2e9a
--- /dev/null
+++ b/android/3rd_party/HoloEverywhere/library/src/org/holoeverywhere/widget/ExpandableListConnector.java
@@ -0,0 +1,594 @@
+
+package org.holoeverywhere.widget;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import android.database.DataSetObserver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+
+public class ExpandableListConnector extends BaseAdapter implements Filterable {
+ static class GroupMetadata implements Parcelable, Comparable<GroupMetadata> {
+ public static final Parcelable.Creator<GroupMetadata> CREATOR =
+ new Parcelable.Creator<GroupMetadata>() {
+ @Override
+ public GroupMetadata createFromParcel(Parcel in) {
+ GroupMetadata gm = GroupMetadata.obtain(
+ in.readInt(),
+ in.readInt(),
+ in.readInt(),
+ in.readLong());
+ return gm;
+ }
+
+ @Override
+ public GroupMetadata[] newArray(int size) {
+ return new GroupMetadata[size];
+ }
+ };
+
+ final static int REFRESH = -1;
+
+ static GroupMetadata obtain(int flPos, int lastChildFlPos, int gPos, long gId) {
+ GroupMetadata gm = new GroupMetadata();
+ gm.flPos = flPos;
+ gm.lastChildFlPos = lastChildFlPos;
+ gm.gPos = gPos;
+ gm.gId = gId;
+ return gm;
+ }
+
+ int flPos;
+ long gId;
+ int gPos;
+ int lastChildFlPos;
+
+ private GroupMetadata() {
+ }
+
+ @Override
+ public int compareTo(GroupMetadata another) {
+ if (another == null) {
+ throw new IllegalArgumentException();
+ }
+
+ return gPos - another.gPos;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(flPos);
+ dest.writeInt(lastChildFlPos);
+ dest.writeInt(gPos);
+ dest.writeLong(gId);
+ }
+ }
+
+ protected class MyDataSetObserver extends DataSetObserver {
+ @Override
+ public void onChanged() {
+ refreshExpGroupMetadataList(true, true);
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ refreshExpGroupMetadataList(true, true);
+ notifyDataSetInvalidated();
+ }
+ }
+
+ static public class PositionMetadata {
+ private static final int MAX_POOL_SIZE = 5;
+ private static ArrayList<PositionMetadata> sPool =
+ new ArrayList<PositionMetadata>(MAX_POOL_SIZE);
+
+ private static PositionMetadata getRecycledOrCreate() {
+ PositionMetadata pm;
+ synchronized (sPool) {
+ if (sPool.size() > 0) {
+ pm = sPool.remove(0);
+ } else {
+ return new PositionMetadata();
+ }
+ }
+ pm.resetState();
+ return pm;
+ }
+
+ static PositionMetadata obtain(int flatListPos, int type, int groupPos,
+ int childPos, GroupMetadata groupMetadata, int groupInsertIndex) {
+ PositionMetadata pm = getRecycledOrCreate();
+ pm.position = ExpandableListPosition.obtain(type, groupPos, childPos, flatListPos);
+ pm.groupMetadata = groupMetadata;
+ pm.groupInsertIndex = groupInsertIndex;
+ return pm;
+ }
+
+ public int groupInsertIndex;
+ public GroupMetadata groupMetadata;
+ public ExpandableListPosition position;
+
+ private PositionMetadata() {
+ }
+
+ public boolean isExpanded() {
+ return groupMetadata != null;
+ }
+
+ public void recycle() {
+ resetState();
+ synchronized (sPool) {
+ if (sPool.size() < MAX_POOL_SIZE) {
+ sPool.add(this);
+ }
+ }
+ }
+
+ private void resetState() {
+ if (position != null) {
+ position.recycle();
+ position = null;
+ }
+ groupMetadata = null;
+ groupInsertIndex = 0;
+ }
+ }
+
+ private final DataSetObserver mDataSetObserver = new MyDataSetObserver();
+ private ExpandableListAdapter mExpandableListAdapter;
+ private ArrayList<GroupMetadata> mExpGroupMetadataList;
+ private int mMaxExpGroupCount = Integer.MAX_VALUE;
+ private int mTotalExpChildrenCount;
+
+ public ExpandableListConnector(ExpandableListAdapter expandableListAdapter) {
+ mExpGroupMetadataList = new ArrayList<GroupMetadata>();
+ setExpandableListAdapter(expandableListAdapter);
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return mExpandableListAdapter.areAllItemsEnabled();
+ }
+
+ boolean collapseGroup(int groupPos) {
+ ExpandableListPosition elGroupPos = ExpandableListPosition.obtain(
+ ExpandableListPosition.GROUP, groupPos, -1, -1);
+ PositionMetadata pm = getFlattenedPos(elGroupPos);
+ elGroupPos.recycle();
+ if (pm == null) {
+ return false;
+ }
+ boolean retValue = collapseGroup(pm);
+ pm.recycle();
+ return retValue;
+ }
+
+ boolean collapseGroup(PositionMetadata posMetadata) {
+ if (posMetadata.groupMetadata == null) {
+ return false;
+ }
+ mExpGroupMetadataList.remove(posMetadata.groupMetadata);
+ refreshExpGroupMetadataList(false, false);
+ notifyDataSetChanged();
+ mExpandableListAdapter.onGroupCollapsed(posMetadata.groupMetadata.gPos);
+ return true;
+ }
+
+ boolean expandGroup(int groupPos) {
+ ExpandableListPosition elGroupPos = ExpandableListPosition.obtain(
+ ExpandableListPosition.GROUP, groupPos, -1, -1);
+ PositionMetadata pm = getFlattenedPos(elGroupPos);
+ elGroupPos.recycle();
+ boolean retValue = expandGroup(pm);
+ pm.recycle();
+ return retValue;
+ }
+
+ boolean expandGroup(PositionMetadata posMetadata) {
+ if (posMetadata.position.groupPos < 0) {
+ throw new RuntimeException("Need group");
+ }
+ if (mMaxExpGroupCount == 0) {
+ return false;
+ }
+ if (posMetadata.groupMetadata != null) {
+ return false;
+ }
+ if (mExpGroupMetadataList.size() >= mMaxExpGroupCount) {
+ GroupMetadata collapsedGm = mExpGroupMetadataList.get(0);
+ int collapsedIndex = mExpGroupMetadataList.indexOf(collapsedGm);
+ collapseGroup(collapsedGm.gPos);
+ if (posMetadata.groupInsertIndex > collapsedIndex) {
+ posMetadata.groupInsertIndex--;
+ }
+ }
+ GroupMetadata expandedGm = GroupMetadata.obtain(
+ GroupMetadata.REFRESH,
+ GroupMetadata.REFRESH,
+ posMetadata.position.groupPos,
+ mExpandableListAdapter.getGroupId(posMetadata.position.groupPos));
+ mExpGroupMetadataList.add(posMetadata.groupInsertIndex, expandedGm);
+ refreshExpGroupMetadataList(false, false);
+ notifyDataSetChanged();
+ mExpandableListAdapter.onGroupExpanded(expandedGm.gPos);
+ return true;
+ }
+
+ int findGroupPosition(long groupIdToMatch, int seedGroupPosition) {
+ int count = mExpandableListAdapter.getGroupCount();
+ if (count == 0) {
+ return AdapterView.INVALID_POSITION;
+ }
+ if (groupIdToMatch == AdapterView.INVALID_ROW_ID) {
+ return AdapterView.INVALID_POSITION;
+ }
+ seedGroupPosition = Math.max(0, seedGroupPosition);
+ seedGroupPosition = Math.min(count - 1, seedGroupPosition);
+ long endTime = SystemClock.uptimeMillis() + AdapterView.SYNC_MAX_DURATION_MILLIS;
+ long rowId;
+ int first = seedGroupPosition;
+ int last = seedGroupPosition;
+ boolean next = false;
+ boolean hitFirst;
+ boolean hitLast;
+ ExpandableListAdapter adapter = getAdapter();
+ if (adapter == null) {
+ return AdapterView.INVALID_POSITION;
+ }
+ while (SystemClock.uptimeMillis() <= endTime) {
+ rowId = adapter.getGroupId(seedGroupPosition);
+ if (rowId == groupIdToMatch) {
+ return seedGroupPosition;
+ }
+ hitLast = last == count - 1;
+ hitFirst = first == 0;
+ if (hitLast && hitFirst) {
+ break;
+ }
+ if (hitFirst || next && !hitLast) {
+ last++;
+ seedGroupPosition = last;
+ next = false;
+ } else if (hitLast || !next && !hitFirst) {
+ first--;
+ seedGroupPosition = first;
+ next = true;
+ }
+ }
+ return AdapterView.INVALID_POSITION;
+ }
+
+ ExpandableListAdapter getAdapter() {
+ return mExpandableListAdapter;
+ }
+
+ @Override
+ public int getCount() {
+ return mExpandableListAdapter.getGroupCount() + mTotalExpChildrenCount;
+ }
+
+ ArrayList<GroupMetadata> getExpandedGroupMetadataList() {
+ return mExpGroupMetadataList;
+ }
+
+ @Override
+ public Filter getFilter() {
+ ExpandableListAdapter adapter = getAdapter();
+ if (adapter instanceof Filterable) {
+ return ((Filterable) adapter).getFilter();
+ } else {
+ return null;
+ }
+ }
+
+ PositionMetadata getFlattenedPos(final ExpandableListPosition pos) {
+ final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
+ final int numExpGroups = egml.size();
+ int leftExpGroupIndex = 0;
+ int rightExpGroupIndex = numExpGroups - 1;
+ int midExpGroupIndex = 0;
+ GroupMetadata midExpGm;
+ if (numExpGroups == 0) {
+ return PositionMetadata.obtain(pos.groupPos, pos.type,
+ pos.groupPos, pos.childPos, null, 0);
+ }
+ while (leftExpGroupIndex <= rightExpGroupIndex) {
+ midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex) / 2 + leftExpGroupIndex;
+ midExpGm = egml.get(midExpGroupIndex);
+ if (pos.groupPos > midExpGm.gPos) {
+ leftExpGroupIndex = midExpGroupIndex + 1;
+ } else if (pos.groupPos < midExpGm.gPos) {
+ rightExpGroupIndex = midExpGroupIndex - 1;
+ } else if (pos.groupPos == midExpGm.gPos) {
+ if (pos.type == ExpandableListPosition.GROUP) {
+ return PositionMetadata.obtain(midExpGm.flPos, pos.type,
+ pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex);
+ } else if (pos.type == ExpandableListPosition.CHILD) {
+ return PositionMetadata.obtain(midExpGm.flPos + pos.childPos
+ + 1, pos.type, pos.groupPos, pos.childPos,
+ midExpGm, midExpGroupIndex);
+ } else {
+ return null;
+ }
+ }
+ }
+ if (pos.type != ExpandableListPosition.GROUP) {
+ return null;
+ }
+ if (leftExpGroupIndex > midExpGroupIndex) {
+ final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex - 1);
+ final int flPos =
+ leftExpGm.lastChildFlPos
+ + pos.groupPos - leftExpGm.gPos;
+
+ return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
+ pos.childPos, null, leftExpGroupIndex);
+ } else if (rightExpGroupIndex < midExpGroupIndex) {
+ final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex);
+ final int flPos =
+ rightExpGm.flPos
+ - (rightExpGm.gPos - pos.groupPos);
+ return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
+ pos.childPos, null, rightExpGroupIndex);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Object getItem(int flatListPos) {
+ final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
+ Object retValue;
+ if (posMetadata.position.type == ExpandableListPosition.GROUP) {
+ retValue = mExpandableListAdapter
+ .getGroup(posMetadata.position.groupPos);
+ } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
+ retValue = mExpandableListAdapter.getChild(posMetadata.position.groupPos,
+ posMetadata.position.childPos);
+ } else {
+ throw new RuntimeException("Flat list position is of unknown type");
+ }
+ posMetadata.recycle();
+ return retValue;
+ }
+
+ @Override
+ public long getItemId(int flatListPos) {
+ final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
+ final long groupId = mExpandableListAdapter.getGroupId(posMetadata.position.groupPos);
+ long retValue;
+ if (posMetadata.position.type == ExpandableListPosition.GROUP) {
+ retValue = mExpandableListAdapter.getCombinedGroupId(groupId);
+ } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
+ final long childId = mExpandableListAdapter.getChildId(posMetadata.position.groupPos,
+ posMetadata.position.childPos);
+ retValue = mExpandableListAdapter.getCombinedChildId(groupId, childId);
+ } else {
+ throw new RuntimeException("Flat list position is of unknown type");
+ }
+ posMetadata.recycle();
+ return retValue;
+ }
+
+ @Override
+ public int getItemViewType(int flatListPos) {
+ final PositionMetadata metadata = getUnflattenedPos(flatListPos);
+ final ExpandableListPosition pos = metadata.position;
+ int retValue;
+ if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+ HeterogeneousExpandableList adapter =
+ (HeterogeneousExpandableList) mExpandableListAdapter;
+ if (pos.type == ExpandableListPosition.GROUP) {
+ retValue = adapter.getGroupType(pos.groupPos);
+ } else {
+ final int childType = adapter.getChildType(pos.groupPos, pos.childPos);
+ retValue = adapter.getGroupTypeCount() + childType;
+ }
+ } else {
+ if (pos.type == ExpandableListPosition.GROUP) {
+ retValue = 0;
+ } else {
+ retValue = 1;
+ }
+ }
+ metadata.recycle();
+ return retValue;
+ }
+
+ PositionMetadata getUnflattenedPos(final int flPos) {
+ final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
+ final int numExpGroups = egml.size();
+ int leftExpGroupIndex = 0;
+ int rightExpGroupIndex = numExpGroups - 1;
+ int midExpGroupIndex = 0;
+ GroupMetadata midExpGm;
+ if (numExpGroups == 0) {
+ return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, flPos,
+ -1, null, 0);
+ }
+ while (leftExpGroupIndex <= rightExpGroupIndex) {
+ midExpGroupIndex =
+ (rightExpGroupIndex - leftExpGroupIndex) / 2
+ + leftExpGroupIndex;
+ midExpGm = egml.get(midExpGroupIndex);
+ if (flPos > midExpGm.lastChildFlPos) {
+ leftExpGroupIndex = midExpGroupIndex + 1;
+ } else if (flPos < midExpGm.flPos) {
+ rightExpGroupIndex = midExpGroupIndex - 1;
+ } else if (flPos == midExpGm.flPos) {
+ return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP,
+ midExpGm.gPos, -1, midExpGm, midExpGroupIndex);
+ } else if (flPos <= midExpGm.lastChildFlPos) {
+ final int childPos = flPos - (midExpGm.flPos + 1);
+ return PositionMetadata.obtain(flPos, ExpandableListPosition.CHILD,
+ midExpGm.gPos, childPos, midExpGm, midExpGroupIndex);
+ }
+ }
+ int insertPosition = 0;
+ int groupPos = 0;
+ if (leftExpGroupIndex > midExpGroupIndex) {
+ final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex - 1);
+ insertPosition = leftExpGroupIndex;
+ groupPos =
+ flPos - leftExpGm.lastChildFlPos + leftExpGm.gPos;
+ } else if (rightExpGroupIndex < midExpGroupIndex) {
+ final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex);
+ insertPosition = rightExpGroupIndex;
+ groupPos = rightExpGm.gPos - (rightExpGm.flPos - flPos);
+ } else {
+ throw new RuntimeException("Unknown state");
+ }
+ return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, groupPos, -1,
+ null, insertPosition);
+ }
+
+ @Override
+ public View getView(int flatListPos, View convertView, ViewGroup parent) {
+ final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
+ View retValue;
+ if (posMetadata.position.type == ExpandableListPosition.GROUP) {
+ retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos,
+ posMetadata.isExpanded(), convertView, parent);
+ } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
+ final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos;
+
+ retValue = mExpandableListAdapter.getChildView(posMetadata.position.groupPos,
+ posMetadata.position.childPos, isLastChild, convertView, parent);
+ } else {
+ throw new RuntimeException("Flat list position is of unknown type");
+ }
+ posMetadata.recycle();
+ return retValue;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
+ HeterogeneousExpandableList adapter =
+ (HeterogeneousExpandableList) mExpandableListAdapter;
+ return adapter.getGroupTypeCount() + adapter.getChildTypeCount();
+ } else {
+ return 2;
+ }
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return mExpandableListAdapter.hasStableIds();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ ExpandableListAdapter adapter = getAdapter();
+ return adapter != null ? adapter.isEmpty() : true;
+ }
+
+ @Override
+ public boolean isEnabled(int flatListPos) {
+ final PositionMetadata metadata = getUnflattenedPos(flatListPos);
+ final ExpandableListPosition pos = metadata.position;
+ boolean retValue;
+ if (pos.type == ExpandableListPosition.CHILD) {
+ retValue = mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos);
+ } else {
+ retValue = true;
+ }
+ metadata.recycle();
+ return retValue;
+ }
+
+ public boolean isGroupExpanded(int groupPosition) {
+ GroupMetadata groupMetadata;
+ for (int i = mExpGroupMetadataList.size() - 1; i >= 0; i--) {
+ groupMetadata = mExpGroupMetadataList.get(i);
+ if (groupMetadata.gPos == groupPosition) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh,
+ boolean syncGroupPositions) {
+ final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
+ int egmlSize = egml.size();
+ int curFlPos = 0;
+ mTotalExpChildrenCount = 0;
+ if (syncGroupPositions) {
+ boolean positionsChanged = false;
+ for (int i = egmlSize - 1; i >= 0; i--) {
+ GroupMetadata curGm = egml.get(i);
+ int newGPos = findGroupPosition(curGm.gId, curGm.gPos);
+ if (newGPos != curGm.gPos) {
+ if (newGPos == AdapterView.INVALID_POSITION) {
+ egml.remove(i);
+ egmlSize--;
+ }
+ curGm.gPos = newGPos;
+ if (!positionsChanged) {
+ positionsChanged = true;
+ }
+ }
+ }
+ if (positionsChanged) {
+ Collections.sort(egml);
+ }
+ }
+ int gChildrenCount;
+ int lastGPos = 0;
+ for (int i = 0; i < egmlSize; i++) {
+ GroupMetadata curGm = egml.get(i);
+ if (curGm.lastChildFlPos == GroupMetadata.REFRESH || forceChildrenCountRefresh) {
+ gChildrenCount = mExpandableListAdapter.getChildrenCount(curGm.gPos);
+ } else {
+ gChildrenCount = curGm.lastChildFlPos - curGm.flPos;
+ }
+ mTotalExpChildrenCount += gChildrenCount;
+ curFlPos += curGm.gPos - lastGPos;
+ lastGPos = curGm.gPos;
+ curGm.flPos = curFlPos;
+ curFlPos += gChildrenCount;
+ curGm.lastChildFlPos = curFlPos;
+ }
+ }
+
+ public void setExpandableListAdapter(ExpandableListAdapter expandableListAdapter) {
+ if (mExpandableListAdapter != null) {
+ mExpandableListAdapter.unregisterDataSetObserver(mDataSetObserver);
+ }
+ mExpandableListAdapter = expandableListAdapter;
+ expandableListAdapter.registerDataSetObserver(mDataSetObserver);
+ }
+
+ void setExpandedGroupMetadataList(ArrayList<GroupMetadata> expandedGroupMetadataList) {
+ if (expandedGroupMetadataList == null || mExpandableListAdapter == null) {
+ return;
+ }
+ int numGroups = mExpandableListAdapter.getGroupCount();
+ for (int i = expandedGroupMetadataList.size() - 1; i >= 0; i--) {
+ if (expandedGroupMetadataList.get(i).gPos >= numGroups) {
+ return;
+ }
+ }
+ mExpGroupMetadataList = expandedGroupMetadataList;
+ refreshExpGroupMetadataList(true, false);
+ }
+
+ public void setMaxExpGroupCount(int maxExpGroupCount) {
+ mMaxExpGroupCount = maxExpGroupCount;
+ }
+}