package gem.kevin.widget;
import gem.kevin.util.ui.ViewUtil;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.View;
import android.widget.GridView;
public class DropableGridView extends GridView implements DropAcceptable {
private static final String TAG = "DropableGridView";
private int[] mLocationOnScreen = new int[2];
private int[] mDragLocationOnScreen = new int[2];
private boolean mChildCanGetDragEvent = true;
private View mCurrentDropHandleView;
private OnDropDelegate mOnDropDelegate;
public DropableGridView(Context context) {
super(context);
}
public DropableGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DropableGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean canAcceptDrop() {
if (mOnDropDelegate != null) {
return mOnDropDelegate.checkDropDataAcceptable(null, this);
}
return false;
}
public OnDropDelegate getOnDropDelegate() {
return mOnDropDelegate;
}
@Override
public boolean onDragEnded(DragEvent event) {
boolean success = event.getResult();
if (mOnDropDelegate != null) {
if (!success) {
mOnDropDelegate.onDropFailed(this);
}
}
return false;
}
@Override
public boolean onDragEntered(DragEvent event) {
getLocationOnScreen(mLocationOnScreen);
return true;
}
@Override
public boolean onDragEvent(DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Log.i(TAG, "DropGV Drag Started.");
return onDragStarted(event);
case DragEvent.ACTION_DRAG_ENTERED:
Log.i(TAG, "DropGV Drag entered.");
return onDragEntered(event);
case DragEvent.ACTION_DRAG_LOCATION:
return onDragMoveOn(event);
case DragEvent.ACTION_DRAG_EXITED:
Log.i(TAG, "DropGV Drag exited.");
return onDragExited(event);
case DragEvent.ACTION_DROP:
Log.i(TAG, "DropGV Drag droped.");
return onDrop(event);
case DragEvent.ACTION_DRAG_ENDED:
Log.i(TAG, "DropGV Drag ended.");
return onDragEnded(event);
}
return super.onDragEvent(event);
}
@Override
public boolean onDragExited(DragEvent event) {
// do nothing
return true;
}
@Override
public boolean onDragMoveOn(DragEvent event) {
Log.i(TAG, "onDragMoveOn");
if (mChildCanGetDragEvent) {
// Let navigators handle the drag event if they can.
return true;
} else {
findAppropriateDragMoveHandle(event);
return true;
}
}
@Override
public boolean onDragStarted(DragEvent event) {
// A drag started event indicates a new drag operation happens,
// when all the created visible navigators should be able to get
// the following drag events
markChildCanGetDragEvent(true);
return true;
}
@Override
public boolean onDrop(DragEvent event) {
if (!mChildCanGetDragEvent) {
if (findAppropriateDropHandle(event)) {
Log.i(TAG, "mCurrentDropHandleView is handling drop.");
return true;
}
}
if (mOnDropDelegate != null) {
Object data = mOnDropDelegate.generateDropData();
boolean result = true;
if (mOnDropDelegate.checkDropDataAcceptable(data, this)) {
result = mOnDropDelegate.handleDrop(data, this);
if (result) {
mOnDropDelegate.onDropSuccess(this);
} else {
mOnDropDelegate.onDropFailed(this);
}
} else {
if (mOnDropDelegate.shouldDispathUnacceptableDropToParent(this)) {
result = super.onDragEvent(event);
} else {
// Because a drop could be obscure when it happens on a GridView
// so we always need to notify the result if it is denied.
mOnDropDelegate.notifyDropDataDenied(data, this);
mOnDropDelegate.onDropFailed(this);
}
}
return result;
}
return false;
}
@Override
public void onHover() {
// do nothing
}
@Override
public void markChildCanGetDragEvent(boolean childCanGetDragEvent) {
mChildCanGetDragEvent = childCanGetDragEvent;
}
public void setOnDropDelegate(OnDropDelegate delegate) {
mOnDropDelegate = delegate;
}
private boolean findAppropriateDragMoveHandle(DragEvent event) {
Log.i(TAG, "Loc of parent: x:" + mLocationOnScreen[0] + " y:"
+ mLocationOnScreen[1]);
mDragLocationOnScreen[0] = (int) (mLocationOnScreen[0] + event.getX());
mDragLocationOnScreen[1] = (int) (mLocationOnScreen[1] + event.getY());
Log.i(TAG, "DGV Drag location relative, x: " + mDragLocationOnScreen[0]
+ " y: " + mDragLocationOnScreen[1]);
boolean moveOnHandleView;
if (mCurrentDropHandleView != null) {
Log.i(TAG, "There is drop handle view, test it!");
// Test if still move on the drop handle view
moveOnHandleView = ViewUtil.isViewContained(mCurrentDropHandleView,
mDragLocationOnScreen[0], mDragLocationOnScreen[1]);
if (!moveOnHandleView) {
// Exit
((DropAcceptable) mCurrentDropHandleView).onDragExited(event);
mCurrentDropHandleView = null;
return false;
} else {
return true;
}
} else {
// Test if there is a new view become drop handle
boolean foundNewDropHandle = false;
for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
moveOnHandleView = ViewUtil.isViewContained(view,
mDragLocationOnScreen[0], mDragLocationOnScreen[1]);
if (moveOnHandleView) {
Log.i(TAG,
"Drag enter child view: " + i + " class: "
+ view.getClass().getSimpleName() + " l: "
+ view.getLeft() + " width: "
+ view.getWidth() + " t: " + view.getTop()
+ " height: " + view.getHeight() + " r: "
+ view.getRight() + " b: "
+ view.getBottom());
if (view instanceof DropAcceptable) {
mCurrentDropHandleView = view;
foundNewDropHandle = true;
((DropAcceptable) mCurrentDropHandleView)
.onDragEntered(event);
}
if (foundNewDropHandle) {
Log.i(TAG, "Find new drop handle view!");
return true;
} else {
Log.i(TAG, "Not find new drop handle view yet!");
}
}
}
return false;
}
}
private boolean findAppropriateDropHandle(DragEvent event) {
Log.i(TAG, "Loc of parent: x:" + mLocationOnScreen[0] + " y:"
+ mLocationOnScreen[1]);
mDragLocationOnScreen[0] = (int) (mLocationOnScreen[0] + event.getX());
mDragLocationOnScreen[1] = (int) (mLocationOnScreen[1] + event.getY());
Log.i(TAG, "DGV Drag location relative, x: " + mDragLocationOnScreen[0]
+ " y: " + mDragLocationOnScreen[1]);
if (mCurrentDropHandleView != null) {
((DropAcceptable) mCurrentDropHandleView).onDrop(event);
mCurrentDropHandleView = null;
return true;
} else {
return false;
}
}
}