diff options
Diffstat (limited to 'library/drag-sort-listview/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java')
-rw-r--r-- | library/drag-sort-listview/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/library/drag-sort-listview/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java b/library/drag-sort-listview/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java new file mode 100644 index 000000000..267c6f869 --- /dev/null +++ b/library/drag-sort-listview/src/main/java/com/mobeta/android/dslv/DragSortCursorAdapter.java @@ -0,0 +1,241 @@ +package com.mobeta.android.dslv; + +import java.util.ArrayList; + +import android.content.Context; +import android.database.Cursor; +import android.util.SparseIntArray; +import android.view.View; +import android.view.ViewGroup; +import android.support.v4.widget.CursorAdapter; + + +/** + * A subclass of {@link android.widget.CursorAdapter} that provides + * reordering of the elements in the Cursor based on completed + * drag-sort operations. The reordering is a simple mapping of + * list positions into Cursor positions (the Cursor is unchanged). + * To persist changes made by drag-sorts, one can retrieve the + * mapping with the {@link #getCursorPositions()} method, which + * returns the reordered list of Cursor positions. + * + * An instance of this class is passed + * to {@link DragSortListView#setAdapter(ListAdapter)} and, since + * this class implements the {@link DragSortListView.DragSortListener} + * interface, it is automatically set as the DragSortListener for + * the DragSortListView instance. + */ +public abstract class DragSortCursorAdapter extends CursorAdapter implements DragSortListView.DragSortListener { + + public static final int REMOVED = -1; + + /** + * Key is ListView position, value is Cursor position + */ + private SparseIntArray mListMapping = new SparseIntArray(); + + private ArrayList<Integer> mRemovedCursorPositions = new ArrayList<Integer>(); + + public DragSortCursorAdapter(Context context, Cursor c) { + super(context, c); + } + + public DragSortCursorAdapter(Context context, Cursor c, boolean autoRequery) { + super(context, c, autoRequery); + } + + public DragSortCursorAdapter(Context context, Cursor c, int flags) { + super(context, c, flags); + } + + /** + * Swaps Cursor and clears list-Cursor mapping. + * + * @see android.widget.CursorAdapter#swapCursor(android.database.Cursor) + */ + @Override + public Cursor swapCursor(Cursor newCursor) { + Cursor old = super.swapCursor(newCursor); + resetMappings(); + return old; + } + + /** + * Changes Cursor and clears list-Cursor mapping. + * + * @see android.widget.CursorAdapter#changeCursor(android.database.Cursor) + */ + @Override + public void changeCursor(Cursor cursor) { + super.changeCursor(cursor); + resetMappings(); + } + + /** + * Resets list-cursor mapping. + */ + public void reset() { + resetMappings(); + notifyDataSetChanged(); + } + + private void resetMappings() { + mListMapping.clear(); + mRemovedCursorPositions.clear(); + } + + @Override + public Object getItem(int position) { + return super.getItem(mListMapping.get(position, position)); + } + + @Override + public long getItemId(int position) { + return super.getItemId(mListMapping.get(position, position)); + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + return super.getDropDownView(mListMapping.get(position, position), convertView, parent); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + return super.getView(mListMapping.get(position, position), convertView, parent); + } + + /** + * On drop, this updates the mapping between Cursor positions + * and ListView positions. The Cursor is unchanged. Retrieve + * the current mapping with {@link getCursorPositions()}. + * + * @see DragSortListView.DropListener#drop(int, int) + */ + @Override + public void drop(int from, int to) { + if (from != to) { + int cursorFrom = mListMapping.get(from, from); + + if (from > to) { + for (int i = from; i > to; --i) { + mListMapping.put(i, mListMapping.get(i - 1, i - 1)); + } + } else { + for (int i = from; i < to; ++i) { + mListMapping.put(i, mListMapping.get(i + 1, i + 1)); + } + } + mListMapping.put(to, cursorFrom); + + cleanMapping(); + notifyDataSetChanged(); + } + } + + /** + * On remove, this updates the mapping between Cursor positions + * and ListView positions. The Cursor is unchanged. Retrieve + * the current mapping with {@link getCursorPositions()}. + * + * @see DragSortListView.RemoveListener#remove(int) + */ + @Override + public void remove(int which) { + int cursorPos = mListMapping.get(which, which); + if (!mRemovedCursorPositions.contains(cursorPos)) { + mRemovedCursorPositions.add(cursorPos); + } + + int newCount = getCount(); + for (int i = which; i < newCount; ++i) { + mListMapping.put(i, mListMapping.get(i + 1, i + 1)); + } + + mListMapping.delete(newCount); + + cleanMapping(); + notifyDataSetChanged(); + } + + /** + * Does nothing. Just completes DragSortListener interface. + */ + @Override + public void drag(int from, int to) { + // do nothing + } + + /** + * Remove unnecessary mappings from sparse array. + */ + private void cleanMapping() { + ArrayList<Integer> toRemove = new ArrayList<Integer>(); + + int size = mListMapping.size(); + for (int i = 0; i < size; ++i) { + if (mListMapping.keyAt(i) == mListMapping.valueAt(i)) { + toRemove.add(mListMapping.keyAt(i)); + } + } + + size = toRemove.size(); + for (int i = 0; i < size; ++i) { + mListMapping.delete(toRemove.get(i)); + } + } + + @Override + public int getCount() { + return super.getCount() - mRemovedCursorPositions.size(); + } + + /** + * Get the Cursor position mapped to by the provided list position + * (given all previously handled drag-sort + * operations). + * + * @param position List position + * + * @return The mapped-to Cursor position + */ + public int getCursorPosition(int position) { + return mListMapping.get(position, position); + } + + /** + * Get the current order of Cursor positions presented by the + * list. + */ + public ArrayList<Integer> getCursorPositions() { + ArrayList<Integer> result = new ArrayList<Integer>(); + + for (int i = 0; i < getCount(); ++i) { + result.add(mListMapping.get(i, i)); + } + + return result; + } + + /** + * Get the list position mapped to by the provided Cursor position. + * If the provided Cursor position has been removed by a drag-sort, + * this returns {@link #REMOVED}. + * + * @param cursorPosition A Cursor position + * @return The mapped-to list position or REMOVED + */ + public int getListPosition(int cursorPosition) { + if (mRemovedCursorPositions.contains(cursorPosition)) { + return REMOVED; + } + + int index = mListMapping.indexOfValue(cursorPosition); + if (index < 0) { + return cursorPosition; + } else { + return mListMapping.keyAt(index); + } + } + + +} |